
On Tue, May 31, 2011 at 2:49 PM, Scott Lawrence
I was under the impression that operations performed in monads (in this case, the IO monad) were lazy. (Certainly, every time I make the opposite assumption, my code fails :P .) Which doesn't explain why the following code fails to terminate:
iRecurse :: (Num a) => IO a iRecurse = do recurse <- iRecurse return 1
main = (putStrLn . show) =<< iRecurse
Any pointers to a good explanation of when the IO monad is lazy?
=== The long story ===
I wrote a function unfold with type signature (([a] -> a) -> [a]), for generating a list in which each element can be calculated from all of the previous elements.
unfold :: ([a] -> a) -> [a] unfold f = unfold1 f []
unfold1 :: ([a] -> a) -> [a] -> [a] unfold1 f l = f l : unfold1 f (f l : l)
Now I'm attempting to do the same thing, except where f returns a monad. (My use case is when f randomly selects the next element, i.e. text generation from markov chains.) So I want
unfoldM1 :: (Monad m) => ([a] -> m a) -> [a] -> m [a]
My instinct, then, would be to do something like:
unfoldM1 f l = do next <- f l rest <- unfoldM1 f (next : l) return (next : rest)
But that, like iRecurse above, doesn't work.
You could use a different type:
type IOStream a = (a, IO (IOStream a))
unfold :: ([a] -> IO a) -> IO (IOStream a) unfold f = let go prev = do next <- f prev return (next, go (next:prev)) in do z <- f [] go [z]
toList :: Int -> IOStream a -> IO [a] toList 0 _ = return [] toList n (x,rest) = do xs <- toList (n-1) rest return (x:xs)
Antoine