I’ve seen mentioned that IO doesn’t satisfy the monad laws, but I didn’t find a simple example showing that. Anybody knows an example? Thanks.
Edit: As ertes and n.m. pointed out, using seq is a bit illegal as it can make any monad fail the laws (combined with undefined). Since undefined may be viewed as a non-terminating computation, it’s perfectly fine to use it.
So the revised question is: Anybody knows an example showing that IO fails to satisfy the monad laws, without using seq? (Or perhaps a proof that IO does satisfy the laws if seq is not allowed?)
tl;dr upfront:
seqis the only way.Since the implementation of
IOis not prescribed by the standard, we can only look at specific implementations. If we look at GHC’s implementation, as it is available from the source (it might be that some of the behind-the-scenes special treatment ofIOintroduces violations of the monad laws, but I’m not aware of any such occurrence),it’s implemented as a (strict) state monad. So any violation of the monad laws
IOmakes, is also made byControl.Monad.State[.Strict].Let’s look at the monad laws and see what happens in
IO:Ignoring the newtype wrapper, that means
return x >>= fbecomes\s -> (f x) s. The only way to (possibly) distinguish that fromf xisseq. (Andseqcan only distinguish it iff x ≡ undefined.)ignoring the newtype wrapper again,
kis replaced by\s -> k s, which again is only distinguishable byseq, and only ifk ≡ undefined.Now, we generally have
per equation 3.17.3.(a) of the language report, so this law holds not only modulo
seq.Summarising,
IOsatisfies the monad laws, except for the fact thatseqcan distinguishundefinedand\s -> undefined s. The same holds forState[T],Reader[T],(->) a, and any other monads wrapping a function type.