[Haskell-cafe] IO is not a monad

Yitzchak Gale gale at sefer.org
Tue Jan 23 08:57:18 EST 2007

I wrote:
>> Prelude> let f .! g = ((.) $! f) $! g
>> Prelude> let f = undefined :: Int -> IO Int
>> Prelude> f `seq` 42
>> *** Exception: Prelude.undefined
>> Prelude> ((>>= f) . return) `seq` 42
>> 42
>> Prelude> ((>>= f) .! return) `seq` 42
>> 42

Duncan Coutts wrote:
> Perhaps I'm missing something but I don't see what's wrong.

The monad laws say that (>>= f) . return must be
identical to f. The above shows that they are not identical
for IO. Therefore, IO is not a monad.

> I think what you're saying is that you want (>>=) to be strict in it's
> second argument. I don't see that this is a requirement of the monad
> laws.

Oh, no, I don't want that at all! Especially not for []!
Where would we be then?

> You'll note that you get the same behaviour for other monads like Maybe
> and [].


I am starting, as a programmer,  from the practical problem
that strictness properties are badly broken in MTL.
But no one seems to want to fix it. Although
it is clear that the current behavior is very wrong,
no one seems to be able to define exactly what the
correct behavior should be.

To understand the problem better myself, I want
to understand better the relationship between
monads in category theory and strictness.

The most common approach seems to be:
Make believe that seq does not exist, and
use the usual Haskell notions of functions
to form a category. Then try to fix up strictness
issues as an afterthought, without regard
to category theory. The result is a mess.
It would be disappointing to me if that is the
best we can do.

Another approach that we came up with
recently on this list is that you can allow
seq - in its current form - as a morphism,
but use .! instead of . as composition in the
category. I find that somewhat attractive,
because .! essentially means "compose
functions while preserving strictness/laziness".

Unfortunately, the above paradox shows that
this is not the complete answer either.

A related issue is the claim that the current
behavior of seq is wrong in some way.
I am not convinced that there is any problem
with the current behavior that \_->_|_ /= _|_,
nor that changing it would solve any

This paradox also shows that an idea mentioned
here a few days ago by Neil Mitchell:

class Seq a where
   seq :: a -> b -> b

is also not sufficient.


More information about the Haskell-Cafe mailing list