It took me a while to see what was really 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 great. Of course, common practice does not use explicit brackets and semicolons when indentation implicitly inserts them. But they should not be sick ... why then the foregoing does not perform parsing?
The real problem is that let opens a new block! The let block has no curly braces, so the indent rule is applied. The block begins with the definition x = [0..10] . Then there is a semicolon that promises defines the following definition, for example:
let x = [0..10] ; y = ...
or even
let x = [0..10] ; y = ...
However, after the semicolon we find print , which even with indentation is less than x . According to the indentation rule, this is equivalent to inserting curly braces, for example:
main = do { let { x = [0..10]; } print x }
but the above is not analyzed. The error message does not apply to implicitly inserted brackets (which would be very confusing!), But only to the next line (in this case, unfortunately, it is almost confusing).
The code can be fixed, for example, by providing explicit curly braces for let :
main = do { let { x = [0..10] }; print x }
Above, the indentation is completely irrelevant: you can add line breaks and / or spaces without affecting parsing (for example, Java, C, etc.). In addition, we can move the semicolon below:
main = do { let x = [0..10] ; print x }
The specified semicolon is on the next line and is less indented than x , implicitly pasting } , which closes the let block. Indentation matters here because let uses the indentation rule. If we add a semicolon more, we can cause the same parsing error that we discovered earlier.
Of course, the most idiomatic choice is to use the indentation rule for the entire code:
main = do let x = [0..10] print x