
Hi Luke, I wrote:
For this reason, I consider it a bug in GHC that return :: IO a is lazy.
Luke Palmer wrote:
Wait a minute...
return undefined >>= const (return 42) = const (return 42) undefined = return 42
But if return undefined = undefined, then that equals;
undefined >>= const (return 42)
Hmm, this is true. OK, so let's explicitly restate the monad laws in this context: (>>= f) .! return == f (>>= return) == id (>>= f) .! (>>= g) == (>>= (>>= f) .! g) David's original problem was with the second law, when you apply the function on both sides to undefined. Let's verify the existence of that problem in the current notation: Prelude> seq ((>>= return) (undefined :: IO Bool)) 42 42 Prelude> seq (id (undefined :: IO Bool)) 42 *** Exception: Prelude.undefined To satisfy the second law, we need: (>>= return) undefined == undefined Why is this not working? Apparently, (>>=) is lazy in its first argument. Then, since return is also lazy, GHC never even looks at the first argument. It just stuffs the operation that includes looking at the first argument into the return-thunk. So there are exactly two ways to satisfy the second law: either (>>=) must be strict in its first argument, or return must be strict. I thought the simplest way out of this would be to make return strict. I didn't notice that there is a problem with it. But you have pointed out that I was being too cavalier. So I now amend my GHC bug report to say: (>>=) must be strict in its first argument. Does that sound better to you? Thanks, Yitz