
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 [].
Yes. 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 problems. 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. Thanks, Yitz