Well, there's lazy, and then there's lazy. mapM
is indeed lazy in that it doesn't do more work than it has to. However, look at the type signature:
mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]
Think about what this means: You give it a function a -> m b
and a bunch of a
s. A regular map
can turn those into a bunch of m b
s, but not an m [b]
. The only way to combine the b
s into a single [b]
without the monad getting in the way is to use >>=
to sequence the m b
s together to construct the list.
In fact, mapM
is precisely equivalent to sequence . map
.
In general, for any monadic expression, if the value is used at all, the entire chain of >>=
s leading to the expression must be forced, so applying sequence
to an infinite list can't ever finish.
If you want to work with an unbounded monadic sequence, you'll either need explicit flow control--e.g., a loop termination condition baked into the chain of binds somehow, which simple recursive functions like mapM
and sequence
don't provide--or a step-by-step sequence, something like this:
data Stream m a = Nil | Stream a (m (Stream m a))
...so that you only force as many monad layers as necessary.
Edit:: Regarding splitRandom
, what's going on there is that you're passing it a Rand
computation, evaluating that with the seed splitRandom
gets, then return
ing the result. Without the splitRandom
, the seed used by the single getRandom
has to come from the final result of sequencing the infinite list, hence it hangs. With the extra splitRandom
, the seed used only needs to thread though the two splitRandom
calls, so it works. The final list of random numbers works because you've left the Rand
monad at that point and nothing depends on its final state.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…