tweag / ormolu

A formatter for Haskell source code
https://ormolu-live.tweag.io
Other
944 stars 83 forks source link

[Question] Odd fixity behavior with <|> #1053

Closed brandonchinn178 closed 1 year ago

brandonchinn178 commented 1 year ago

For the following input code:

foo =
  1 <$ bar1
    <|> 2 <$ bar2
    <|> 3 <$ bar3

Ormolu formats it as

foo =
  1
    <$ bar1
      <|> 2
    <$ bar2
      <|> 3
    <$ bar3

Since <$ binds more tightly than <|>, this seems like odd formatting. Indeed, Ormolu thinks this is the correct format:

foo =
  1
    <$ bar1 <|> 2
    <$ bar2 <|> 3
    <$ bar3

Is this intended behavior?

For reference:

infixl 4 <$
infixl 3 <|>
amesgen commented 1 year ago

Note that <|> is not in the Prelude, so you e.g. import Control.Applicative to make Ormolu aware of its fixity. If you do not do that, Ormolu assumes that <|> has the default fixity infixl 9, which explains the outputs you posted in this issue.

With that import, Ormolu formats your two inputs like this:

InputOutput
```haskell import Control.Applicative foo = 1 <$ bar1 <|> 2 <$ bar2 <|> 3 <$ bar3 foo = 1 <$ bar1 <|> 2 <$ bar2 <|> 3 <$ bar3 ``` ```haskell import Control.Applicative foo = 1 <$ bar1 <|> 2 <$ bar2 <|> 3 <$ bar3 foo = 1 <$ bar1 <|> 2 <$ bar2 <|> 3 <$ bar3 ```

Now, I think the first foo is formatted just as you expected. The second foo is formatted like this due to following principle from the README:

This means that the choices between single-line/multi-line layouts in certain situations are made by the user, not by an algorithm.

When we insert the implicit parentheses explicitly for the second foo, we get

foo =
  (1
    <$ bar1) <|> (2
    <$ bar2) <|> (3
    <$ bar3)

Ormolu now sees that all of the three occurrences of x <$ barx are multi-line, so it respects that choice in the output.

Hope that answers the question!

brandonchinn178 commented 1 year ago

🤦‍♂️ once again, a stupid mistake for the world to see. Sorry about that, thanks a ton!