Yitzchak Gale gale at sefer.org
Wed Mar 3 10:16:32 EST 2010

```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
```