The Maybe monad has a bind function that is strict in its arguments:
The IO monad however has a non-strict bind function:
And so does the strict State monad:
It's easy to see in the source code:
m >>= k to Weak Head Normal Form, you only need to go as far as the
StateT constructor; you don't need to touch any of the parameters. I suppose something similar happens with IO.
What's so strict then about the IO monad and the strict State monad? Their run functions. This:
As opposed to this:
Notice how in the strict case putting the expression in WHNF with
seq is enough to trigger the exception.
Of course, with IO we don't have a explicit run function (one that isn't evil, I mean). We just put the IO action into
Notice however that even the strict State monad is not too strict:
This doesn't trigger an exception, either:
But this does: