1

OK, so here's a weird one.

This works perfectly:

test = do
  x <- [1..5]
  y <- [1..5]
  [x+y, x-y]

But this:

test = do
  x <- [1..5]
  y <- [1..5]
  [
    x+y,
    x-y
  ]

fails miserably. GHC utterly refuses to parse this. No matter how I fidget with it, I can't seem to convince GHC to allow me to spread the list across multiple lines. Which is a problem, because if you replace x+y and x-y with really big expressions, it quickly becomes hard to read...

Does anybody know why isn't this working, and how can I force it to work? (Or at least do something that looks legible?)

Will Ness
  • 70,110
  • 9
  • 98
  • 181
MathematicalOrchid
  • 61,854
  • 19
  • 123
  • 220
  • another case in point for always using explicit braces and semicolons (*especially* in teaching materials). – Will Ness Jul 08 '17 at 11:05
  • If you have really big expressions, use a `let` expression to define temporary names for them. – chepner Jul 08 '17 at 12:53

3 Answers3

4

After do, each line which starts on the same column as the first word after do starts a new entry. With explicit braces, your code is equivalent to

test = do
  { x <- [1..5]
  ; y <- [1..5]
  ; [
      x+y,
      x-y
  ; ]
  }

This is due to the indentation rules. As we can see, the last semicolon should not be there -- to avoid it, we should indent the last line more.

chi
  • 111,837
  • 3
  • 133
  • 218
2

If I parse this, I get the following error:

File.hs:10:3: error:
    parse error (possibly incorrect indentation or mismatched brackets)

I think the parsers simply sees the closing square bracket ] as a new statement. And it complains that the previous statement had no closing bracket (and the new one a closing bracket without an opening bracket). If you push it one column to the right, it parses correctly (at least with GHC-8.0.2)

test = do
  x <- [1..5]
  y <- [1..5]
  [
    x+y,
    x-y
   ] -- one space to the right

As long as you do not go back to the previous indentation level (here one space to the left), it should probably be fine. Since the compiler will see it as one do-statement.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Huh. Really weird that you have to indent *incorrectly* in order to *fix* the indentation rule... I also discovered that you can use a superfluous `let` block to get rid of this. Still annoying though. – MathematicalOrchid Jul 08 '17 at 09:16
  • @MathematicalOrchid well, depends on what you call “correct”. The rule that opening and closing brackets should be indented to the same level is not standard, and IMO doesn't make much sense either. What I find more annoying is that you also can't indent _commata_ to the same level as their precededing bracket in such a case. — Note that in case of a `do` block, the issue is easier to circumvent than `let` – it's sufficient to write `> id [ x+y` \n `>   , x-y ]`. (Possibly that would be more confusing though, so I don't really recommend this.) – leftaroundabout Jul 08 '17 at 09:24
2

Here are a couple of possible ways to write this legally:

test = do
  [x,y] <- replicateM 2 [1..5]
  [
    x+y
   ,x-y
   ]

test = do
  [x,y] <- replicateM 2 [1..5]
  [ x+y
   ,x-y ]

test = do
  [x,y] <- replicateM 2 [1..5]
  [ x+y ,
    x-y ]

test = do
  [x,y] <- replicateM 2 [1..5]
  id [ x+y
     , x-y ]

test = do
  [x,y] <- replicateM 2 [1..5]
  id [
       x+y,
       x-y
     ]

test = do
  [x,y] <- replicateM 2 [1..5]
  ([
     x+y,
     x-y
   ])
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319