lspitzner / brittany

haskell source code formatter
GNU Affero General Public License v3.0
690 stars 72 forks source link

Fails with multiple binders in let-in in do-notation #290

Open tfausak opened 4 years ago

tfausak commented 4 years ago

Given the following input:

main = do let { one = 1; two = 2 } in print ( one + two )

Brittany (version 0.12.1.1) fails and produces this output:

ERROR: brittany pretty printer returned syntactically invalid result.
main = do
  let one = 1
      two = 2
  in  print (one + two)

If there's only one binder in the let and it's short enough, Brittany produces output that works:

-- input
main = do let { one = 1 } in print one
-- output
main = do
  let one = 1 in print one

GHC is fine with let ... in ... inside do notation as long as everything after the let is indented enough. It's possible to format the first example using layout like so:

main = do
  let
    one = 1
    two = 2
    in print ( one + two )
lspitzner commented 4 years ago

Thanks for the report, need to keep track of this.

I have thought about this briefly before, and I thought we'd be able to transform it into do's variant of let (the one without in). But that does not work in general, because you can have recursive bindings:

main = do
  let { x = 1 : y ; y = 2 : x } in print (take 10 x)
-- perfectly valid but
main = do
  let x = 1 : y -- kaboom
  let y = 1 : x
  print (take 10 x)

So your last suggestion is the only working solution I think.

tfausak commented 4 years ago

Alternatively you may be able to drop the in, although that might lead to weird scoping problems.

main = do
  let one = 1
      two = 2
  print ( one + two )