I am puzzled. I can write this:
import Control.Monad
main = print $ head $ (foldr (.) id [f, g]) [3]
where f = (1:)
g = undefined
<
It depends on which monad you're working with, and how its (>>=)
operator is defined.
In the case of Maybe
, (>>=)
is strict in its first argument, as Daniel Fischer explained.
Here are some results for a handful of other monads.
> :set -XNoMonomorphismRestriction
> let foo = (const (return 42) <=< undefined <=< return) 3
> :t foo
foo :: (Num t, Monad m) => m t
Identity: Lazy.
> Control.Monad.Identity.runIdentity foo
42
IO: Strict.
> foo :: IO Integer
*** Exception: Prelude.undefined
Reader: Lazy.
> Control.Monad.Reader.runReader foo "bar"
42
Writer: Has both a lazy and a strict variant.
> Control.Monad.Writer.runWriter foo
(42,())
> Control.Monad.Writer.Strict.runWriter foo
*** Exception: Prelude.undefined
State: Has also both a strict and a lazy version.
> Control.Monad.State.runState foo "bar"
(42,"*** Exception: Prelude.undefined
> Control.Monad.State.Strict.runState foo "bar"
*** Exception: Prelude.undefined
Cont: Strict.
> Control.Monad.Cont.runCont foo id
*** Exception: Prelude.undefined
The bind for Maybe
is strict in the first argument.
Just v >>= f = f v
Nothing >>= f = Nothing
So when you try
Just v >>= undefined >>= \_ -> Nothing
you hit
undefined v >>= \_ -> Nothing
and the implementation needs to find out whether undefined v
is Nothing
or Just something
to see which equation of (>>=)
to use.
On the other hand,
Nothing >>= undefined
determines the result without looking at the second argument of (>>=)
.