This is not a flaw with the Cont
monad so much as sequence
. You can get similar results for Either
, for example:
import Control.Monad.Instances ()
xs :: [Either a Int]
xs = map Right [0..] -- Note: return = Right, for Either
ys :: Either a [Int]
ys = sequence xs
You can't retrieve any elements of ys
until it computes the entire list, which will never happen.
Also, note that: sequence (map f xs) = mapM f xs
, so we can simplify this example to:
>>> import Control.Monad.Instances
>>> mapM Right [0..]
<Hangs forever>
There are a few monads where mapM
will work on an infinite list of values, specifically the lazy StateT
monad and Identity
, but they are the exception to the rule.
Generally, mapM
/sequence
/replicateM
(without trailing underscores) are anti-patterns and the correct solution is to use pipes
, which allows you to build effectful streams that don't try to compute all the results up front. The beginning of the pipes
tutorial describes how to solve this in more detail, but the general rule of thumb is that any time you write something like:
example1 = mapM f xs
example2 = sequence xs
You can transform it into a lazy Producer
by just transforming it to:
example1' = each xs >-> Pipes.Prelude.mapM f
example2' = each xs >-> Pipes.Prelude.sequence
Using the above example with Either
, you would write:
>>> import Pipes
>>> let xs = each [0..] >-> mapM Right :: Producer Int (Either a) ()
Then you can lazily process the stream without generating all elements:
>>> Pipes.Prelude.any (> 10) xs
Right True