indentation with let and do

Hi the list, why do this function doesn't compile (parse error): test :: Bool -> IO () test foo = do let bar = case foo of True -> "Foo"; False -> "Bar" return () while this one does (just adding one space in front of True and False): test :: Bool -> IO () test foo = do let bar = case foo of True -> "Foo"; False -> "Bar" return () Thanks!! Corentin

The first version has bar True and False all at the same indentation level.
As such they are seen as standalone expressions, rather than being nested
under the one introduced by bar.
See http://en.wikibooks.org/wiki/Haskell/Indentation
On Thu, Oct 3, 2013 at 8:31 PM, Corentin Dupont
Hi the list, why do this function doesn't compile (parse error):
test :: Bool -> IO () test foo = do let bar = case foo of True -> "Foo"; False -> "Bar" return ()
while this one does (just adding one space in front of True and False):
test :: Bool -> IO () test foo = do let bar = case foo of True -> "Foo"; False -> "Bar" return ()
Thanks!! Corentin
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Thu, Oct 3, 2013 at 2:31 PM, Corentin Dupont
test :: Bool -> IO () test foo = do let bar = case foo of True -> "Foo"; False -> "Bar" return ()
while this one does (just adding one space in front of True and False):
test :: Bool -> IO () test foo = do let bar = case foo of True -> "Foo"; False -> "Bar" return ()
Do you understand how layout works? Informally, something that is more indented is a continuation of the previous expression, while something equally or less indented is a new expression. In this case, the previous expression is `bar = case foo of` and indenting `True` to the same level as `bar` means you have ended the expression starting with `bar =`. Adding just one extra space indicates that it's still part of `bar =`. (ghc is actually being somewhat lenient here; strictly speaking, you are not indented beyond the `case` so it should have ended the `case` expression. ghc allows some sloppiness like this when there absolutely must be something else after, but there are limits mostly imposed by layout introducers like `let` and `do`.) -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

On Thu, Oct 3, 2013 at 9:44 PM, Brandon Allbery
On Thu, Oct 3, 2013 at 2:31 PM, Corentin Dupont
wrote:
test :: Bool -> IO () test foo = do let bar = case foo of True -> "Foo"; False -> "Bar" return ()
while this one does (just adding one space in front of True and False):
test :: Bool -> IO () test foo = do let bar = case foo of True -> "Foo"; False -> "Bar" return ()
Do you understand how layout works? Informally, something that is more indented is a continuation of the previous expression, while something equally or less indented is a new expression. In this case, the previous expression is `bar = case foo of` and indenting `True` to the same level as `bar` means you have ended the expression starting with `bar =`. Adding just one extra space indicates that it's still part of `bar =`.
(ghc is actually being somewhat lenient here; strictly speaking, you are not indented beyond the `case` so it should have ended the `case` expression. ghc allows some sloppiness like this when there absolutely must be something else after, but there are limits mostly imposed by layout introducers like `let` and `do`.)
Brandon, Indentation of 'case' itself doesn't matter. The layout is introduced by 'of', and then it's the indentation of the lexeme which follows 'of' that matters. So GHC is correct here. Roman

Thanks to all for your replies!
I asked the question because I often make this kind of transformations
(please don't mind the non-sensical example):
test :: Bool -> IO ()
test foo = do
bar <- case foo of
True -> return "Foo"
False -> return "Bar"
return ()
into
test :: Bool -> IO ()
test foo = do
let bar = case foo of
True -> "Foo"
False -> "Bar"
return ()
And was wondering why can't I maintain the initial (and nicer) indentation.
But since let allows for several bindings, it make sense...
Best,
Corentin
On Thu, Oct 3, 2013 at 8:31 PM, Corentin Dupont
test :: Bool -> IO () test foo = do let bar = case foo of True -> "Foo"; False -> "Bar" return ()

Imagine if bar was a toplevel function
bar = case foo of
True -> " Foo";
False -> "Bar";
Keep in mind that indentation level starts at the function name, not at the
let keyword.
On Thu, Oct 3, 2013 at 2:31 PM, Corentin Dupont
Hi the list, why do this function doesn't compile (parse error):
test :: Bool -> IO () test foo = do let bar = case foo of True -> "Foo"; False -> "Bar" return ()
while this one does (just adding one space in front of True and False):
test :: Bool -> IO () test foo = do let bar = case foo of True -> "Foo"; False -> "Bar" return ()
Thanks!! Corentin
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (5)
-
AlanKim Zimmerman
-
Brandon Allbery
-
Corentin Dupont
-
David McBride
-
Roman Cheplyaka