Hi,
While playing around with IO and the do notation, I stumbled across an interesting error.
The following cannot be compiled and results in an “error: parse error on input ‘}’” error:
strlen = do { putStr "Enter"; input <- getLine; let n = show (length input); putStrLn (n ++ " characters")}
However, if you add the in after the let, or add a new line after the let expression, it compiles without errors.
strlen = do { putStr "Enter"; input <- getLine; let n = show (length input) in putStrLn (n ++ " characters")}
strlen = do { putStr "Enter"; input <- getLine; let n = show (length input)
;putStrLn (n ++ " characters")}
Is there a reason for this behavior or is this even a compiler bug?
I tested this with GHC 9.4.8.
L (t : ts) (m : ms) = } : (L (t : ts) ms) if m∕ = 0 and parse-error(t)
This rule, for emitting implicit closing braces, requires m/=0 (which would be true, because it can be zero only if the opening brace is explicit)
The parse-error trick means that it, when reading the putStrLn token, can’t insert the closing brace. The requirements are that it
would be a parse error to have the putStrLn not followed by a closing brace (not fulfilled, since even though putStrLn alone lacks a =, it is still a valid prefix. I.e. the inner let block could be assigning the identifier putStrLn)
andnot be a parse error to have a closing brace inserted before putStrLn (fulfilled)
So in summary, it has only one token look-ahead, which results in too many tokens getting included into the inner layout. When the final explicit closing brace appears, these are our options:
pattern
generation
note
L (} : ts) (0 : ms)
=
} : (L ts ms)
(Note 3)
L (} : ts) ms
=
parse-error
(Note 3)
The first rule can’t fire, since we’re in an implicit context. So the second rule fires and we have the parse-error.