Consider the following function:
oddness :: Maybe Int
oddness = do
let a = Just 1 :: Maybe Int
b <- a
return b
Perfectly fine, albeit contrived, redundant, etc. Bear with me. Now consider what happens if we change the value of a:
oddness :: Maybe Int
oddness = do
let a = Nothing :: Maybe Int
b <- a
return b
This looks odd, because it looks like we're extracting the value from a into b, and then passing it to return - it looks like there's some Int we extract from Nothing, and calling return converts it back to Nothing.
But of course, we know that this do-notation desugars to something like:
oddness :: Maybe Int
oddness =
let a = Nothing :: Maybe Int
in a >>= \b -> return b
And recall the definition of (>>=) for Maybe:
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= _ = Nothing
So what's happening here is that what's on the right of (>>=) remains unevaluated, and Nothing is the result. Mystery solved.