It's not intuitive, but it's straightforward once you understand the semantics. There are basically two cases. Case 1:
x <- monadicFunctionA
monadicFunctionB
is rewritten as: monadicFunctionA >>= \x -> monadicFunctionB
The important thing here is that x is just the variable name in an lambda expression that you don't see. Case 2: monadicFunctionA
monadicFunctionB
is rewritten as: monadicFunctionA >> monadicFunctionB
Where >> === >>= \_ ... . Given these rules, you can approximate do-notation like so: monadicFunctionA >>=
\x -> monadicFunctionB >>
monadicFunctionC ...