UPDATE: Okay this question becomes potentially very straightforward.
q <- mapM return [1..]
Why does this never return
Let's talk about this in a more generic context.
As the other answers said, the mapM
is just a combination of sequence
and map
. So the problem is why sequence
is strict in certain Monad
s. However, this is not restricted to Monads
but also Applicative
s since we have sequenceA
which share the same implementation of sequence
in most cases.
Now look at the (specialized for lists) type signature of sequenceA
:
sequenceA :: Applicative f => [f a] -> f [a]
How would you do this? You were given a list, so you would like to use foldr
on this list.
sequenceA = foldr f b where ...
--f :: f a -> f [a] -> f [a]
--b :: f [a]
Since f
is an Applicative
, you know what b
coule be - pure []
. But what is f
?
Obviously it is a lifted version of (:)
:
(:) :: a -> [a] -> [a]
So now we know how sequenceA
works:
sequenceA = foldr f b where
f a b = (:) <$> a <*> b
b = pure []
or
sequenceA = foldr ((<*>) . fmap (:)) (pure [])
Assume you were given a lazy list (x:_|_)
. The above definition of sequenceA
gives
sequenceA (x:_|_) === (:) <$> x <*> foldr ((<*>) . fmap (:)) (pure []) _|_
=== (:) <$> x <*> _|_
So now we see the problem was reduced to consider weather f <*> _|_
is _|_
or not. Obviously if f
is strict this is _|_
, but if f is not strict, to allow a stop of evaluation we require <*>
itself to be non-strict.
So the criteria for an applicative functor to have a sequenceA
that stops on will be
the <*>
operator to be non-strict. A simple test would be
const a <$> _|_ === _|_ ====> strict sequenceA
-- remember f <$> a === pure f <*> a
If we are talking about Moand
s, the criteria is
_|_ >> const a === _|_ ===> strict sequence