6

From some book I have the following code snippets

mutableUpdateIO :: Int -> IO (MV.MVector RealWorld Int)
mutableUpdateIO n = do
  mvec <- GM.new (n + 1)
  go n mvec
  where
    go 0 v = return v
    go n v = (MV.write v n 0) >> go (n - 1) v

mutableUpdateST :: Int -> V.Vector Int
mutableUpdateST n =
  runST $ do
    mvec <- GM.new (n + 1)
    go n mvec
  where
    go 0 v = V.freeze v
    go n v = (MV.write v n 0) >> go (n - 1) v

like hindent indents them. Now I want to introduce all braces and semicolons, so the whitespace isn't relevant any more. Just because I am curious.

The second example suggests, that the where belongs to the whole runST $ do ... expression, but the first example suggests, that the where is somehow a part of the go n mvec statement. Reading in Haskell Report Chapter 2.7 I tried to introduce braces and semicolons in the first example like

mutableUpdateIO :: Int -> IO (MV.MVector RealWorld Int)
mutableUpdateIO n = do {
  mvec <- GM.new (n + 1);
  go n mvec;
  where {
    go 0 v = return v;
    go n v = (MV.write v n 0) >> go (n - 1) v;
  } ; }

But I get a parsing error. Why is that?

Why is the layout hindent produces for the first example mutableUpdateIO valid Haskell? Shouldn't the braces and semicolons be introduced like in my above try?

typetetris
  • 4,586
  • 16
  • 31
  • `where` is separate from the `do` afaik. I think where's automatically have function scope. – Carcigenicate Jul 25 '17 at 14:51
  • Related to: https://stackoverflow.com/questions/9721354/in-haskell-what-is-the-scope-of-a-where-clause-when-dealing-with-guards – Carcigenicate Jul 25 '17 at 14:52
  • 10
    `do ...` is an expression. `where` never attaches to expressions, only to declarations. – melpomene Jul 25 '17 at 14:54
  • 5
    `do { ..; where { .. } }` is never valid, because as @melpomene says, `where` is never associated with an expression. The first program with explicit layout is `do { .. } where { .. }` – user2407038 Jul 25 '17 at 15:09
  • 2
    For what it is worth, in my personal style I never mix `do` and `where`. More in general, I try to avoid `where` except after `... = expr` with `expr` being 1 or at most 2 lines long. Since `do` is longer than that, `where` is avoided. Further, `do` allows `let` inside it, so one can use that instead. – chi Jul 25 '17 at 16:09

1 Answers1

8

The where blocks belong neither to the runST $ do ... expression nor to the go n mvec statement; they belong to the mutableUpdateIO n = ... declaration and the mutableUpdateST n = ... declaration. The braces and semicolons should go like this:

mutableUpdateIO :: Int -> IO (MV.MVector RealWorld Int)
mutableUpdateIO n = do {
  mvec <- GM.new (n + 1);
  go n mvec;
  } where {
    go 0 v = return v;
    go n v = (MV.write v n 0) >> go (n - 1) v;
  }

The relevant sentence from the informal description in the Report in chapter 2.7 is this:

A close brace is also inserted whenever the syntactic category containing the layout list ends; that is, if an illegal lexeme is encountered at a point where a close brace would be legal, a close brace is inserted.

Since where is an illegal lexeme inside an expression, this ends the do block and a close brace is inserted there. This also explains why the layout hindent produced was legal.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380