Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly use monadic expressions in Haskell without getting parse errors?

Tags:

haskell

monads

I'm running GHC version 7.8.3 on Windows 7.

Ok, this is not about fancy code snippets. I'm just trying not be a noob here and actually compile something in a way that vaguely resembles the structure of side-effect languages.

I have the following code:

main = 
    do {
    let x = [0..10];
    print x
}

I've learned here, that the keyword do is a fancy syntactic sugar for fancy monadic expressions. When I try to compile it, I get the following error:

main.hs:4:1: parse error on input 'print'

And I've learned in this other question, that tabs in Haskell are evil, so I've tried to omit them:

main = 
    do {
let x = [0..10];
print x
}

And I've failed miserably, because the parse error persists.

I've also learned here, that print is a syntactic sugar for the fancy equivalent:

main = 
    do {
    let x = [0..10];
    putStrLn $ show x 
}

But then I get this error instead:

main.hs:4:9: parse error on input 'putStrLn'

Trying to face my despair, I've tried to omit the let keyword, after reading this answer:

main = 
    do {
    x = [0..10];
    print x 
}

And then I get:

main.hs:4:1: parse error on input '='

And in a final useless attempt, I've even tried to omit the ';' like this:

main = 
    do {
    let x = [0..10]
    print x 
}

And got:

main.hs:4:1: parse error on input 'print'

So,

How to properly use monadic expressions in Haskell without getting parse errors? Is there any hope?

like image 834
Ericson Willians Avatar asked Jun 07 '15 15:06

Ericson Willians


3 Answers

It took me a while to see what was actually going on here:

main = 
    do {
    let x = [0..10];
    print x
}

The above looks as if we have a do with two statements, which is perfectly fine. Sure, it is not common practice to use explicit braces-and-semicolons when indentation implicitly inserts them. But they shouldn't hurt... why then the above fails parsing?

The real issue is that let opens a new block! The let block has no braces, so the indentation rule applies. The block starts with the definition x = [0..10]. Then a semicolon is found, which promises that another definition is following e.g.

let x = [0..10] ; y = ...

or even

let x = [0..10] ;
      y = ...      -- must be indented as the x above, or more indented

However, after the semicolon we find print, which is even indented less than x. According to the indentation rule, this is equivalent to inserting braces like:

main = 
    do {
    let { x = [0..10]; }
    print x
}

but the above does not parse. The error message does not refer to the implicitly inserted braces (which would be very confusing!), but only to the next line (nearly as confusing in this case, unfortunately).

The code can be fixed by e.g. providing explicit braces for let:

main = do { let { x = [0..10] };
            print x }

Above, indentation is completely irrelevant: you can add line breaks and/or spaces without affecting the parsing (e.g. as in Java, C, etc.). Alternatively, we can move the semicolon below:

main = do { let x = [0..10]
          ; print x }

The above semicolon is on the next line and is less indented than x, implicitly inserting a } which closes the let block. Here indentation matters, since let uses the indentation rule. If we indent the semicolon more, we can cause the same parse error we found earlier.

Of course, the most idiomatic choice is using the indentation rule for the whole code:

main = do let x = [0..10]
          print x
like image 134
chi Avatar answered Oct 01 '22 23:10

chi


I was about to say, with no useful information, that

main =  do 
    let x = [0..10]
    print x

Was working for me, but I'm now off to read about the in within the braces.

As a slight aside, I found http://echo.rsmw.net/n00bfaq.html quite handy for reading about identation/formatting.

like image 44
Chris Avatar answered Oct 02 '22 00:10

Chris


main = do let x = [0..10]
          print x

works for me

and so does

main = do { let x = [0..10]
            in print x }

I think you're trying to mix some different syntax options up.

like image 23
Jay Kominek Avatar answered Oct 02 '22 01:10

Jay Kominek