I have a function f :: [a] -> b
that operates on infinite lists (e.g. take 5
, takeWhile (< 100) . scanl (+) 0
and so on). I want to feed this function with values generated by strict monadic actions (e.g. randomIO
).
From this question, I've learned that the repeat
and sequence
trick approach does not work for strict monads, as the example below show:
import Control.Monad.Identity
take 5 <$> sequence (repeat $ return 1) :: Identity [Int]
-- returns `Identity [1,1,1,1,1]`
-- works because Identity is non-strict
take 5 <$> sequence (repeat $ return 1) :: IO [Int]
-- returns `*** Exception: stack overflow`
-- does not work because IO is strict
So, instead, I thought about using the function "inside" the monadic context. I was inspired by this circular programming example and tried:
let loop = do
x <- return 1
(_, xs) <- loop
return (take 5 xs, x:xs)
in fst loop :: Identity [Int]
-- Overflows the stack
and
import Control.Monad.Fix
fst <$> mfix (\(_, xs) -> do
x <- return 1
return (take 5 xs, x:xs)) :: Identity [Int]
-- Overflows the stack
and even
{-# LANGUAGE RecursiveDo #-}
import System.Random
loop' = mdo
(xs', xs) <- loop xs
return xs'
where loop xs = do
x <- randomIO
return (take 5 xs, x:xs)
print $ loop'
-- Returns a list of 5 identical values
But none of these works. I also tried a Conduit
approach which did not work either even in the Identity
case:
import Conduit
runConduitPure $ yieldMany [1..] .| sinkList >>= return . take 5
Therefore I would like to know:
Why none of the "circular" approaches above work?
If there exists a solution to this that does not involve
unsafeInterleaveIO
. (maybeiteratee
s,Arrow
s?)