
On Sun, 2005-04-24 at 23:16 -0700, Michael Vanier wrote:
I've been trying to generate an infinite list of random coin flips in GHC 6.4, and I've come across some strange behavior:
---------------------------------------------------------------------- import System.Random
data Coin = H | T deriving (Eq, Show)
-- Generate a random coin flip. coinFlip :: IO Coin coinFlip = do b <- getStdRandom random return (bool2coin b) where bool2coin True = H bool2coin False = T
-- Generate an infinite list of coin flips. coinFlips :: IO [Coin] coinFlips = sequence cfs where cfs = (coinFlip : cfs)
-- Print n of them. test :: Int -> IO () test n = do f <- coinFlips print (take n f) ----------------------------------------------------------------------
Now when I do "test 1" (for instance), it hangs forever. It seems as if there is some kind of strictness constraint going on that I don't understand. My understanding is that cfs is an infinite list of (IO Coin), sequence lifts this to be IO [Coin] where [Coin] is an infinite list, and then test should extract the infinite list of coin flips into f, take some number of them, and print them. But instead, the system appears to be trying to compute all the coin flips before taking any of them. Why is this, and how do I fix it?
My first guess is that this is because sequence is strict in it's list. This is the normal behaviour that you would expect for this function since otherwise the side effects from all the IO actions are not going to happen before it returns (which is the ordinary behaviour for IO actions; one of the main purposes of the IO monad is for sequencing side effects). You can lazily defer IO actions using unsafeInterleaveIO. However in this case that's probably not the most elegant approach. It might be better to make the coinFlip function pure (ie not in the IO monad) and instead to pass it a random number generator which it returns as an extra component of the result (having extracted a random value using 'random'). Then you can use getStdGen once and pass the result to a function which generates an infinite lazy list of random numbers by threading the generator between calls to coinFlip. (Or if you want to cheat you can use randoms which will do all this for you) See: http://haskell.org/ghc/docs/latest/html/libraries/base/System.Random.html Duncan