Note that you can observe this effect with not just do , but also let , if , \ , case , the extensions mdo and proc …and the dread unary - . I cannot think of a case in which this is ambiguous except for unary - . Here’s how the grammar is defined in the Haskell 2010 Language Report, §3: Expressions.

exp → infixexp :: [context =>] type | infixexp infixexp → lexp qop infixexp | - infixexp | lexp lexp → \ apat1 … apatn -> exp | let decls in exp | if exp [;] then exp [;] else exp | case exp of { alts } | do { stmts } | fexp fexp → [fexp] aexp aexp → ( exp ) | …

There just happens to be no case defined in fexp (function application) or aexp (literal expression) that allows an unparenthesised lexp (lambda, let , etc.). I would consider this a bug in the grammar.