For example, this monadic expression is equivalent to the recently shown do block.

main =
   getLine >>=
     (\x-> 
        (getLine >>= putStrLn) 
        >> putStrLn x 
     )

I have created three substitution rules to give you an intuitive understanding of why do blocks are just syntactic sugar for underlying expressions involving (>>) and (>>=). My rules are somewhat sloppy. We need intuition here more than precise math. In particular we need to understand that what looks like variable assignment is really just parameter passing.

Although sloppy, these rules can work for you almost all the time. Make sure that you are not mixing up two different monads with one substitution and be careful not to allow a symbol that is used in two different ways to become used in just one way. Finally, cooperate with the type checker.