
Niko Korhonen wrote:
So, in short, how do I do this without getting into an infinite loop:
tpdfs :: (Int, Int) -> IO [Int] tpdfs (low, high) = do first <- getStdRandom (randomR (low, high)) second <- getStdRandom (randomR (low, high)) let r = (first + second) `div` 2 rest <- tpdfs (low, high) -- (A) return (r : rest) -- (B)
(A) will be executed before (B) because of the IO monad. But you want r to be returned before rest is computed. I would split tpdfs in two functions: a pure function converting a infinite list of random numbers to another infinite list of random numbers, and an IO-function creating the original infinite list of random numbers: tpdfs' :: [Int] -> [Int] tpdfs' (x:y:rest) = (x + y) `div` 2 : tpdfs' rest tpdfs :: (Int, Int) -> IO [Int] tpdfs range = do gen <- newStdGen return (tpdfs' (randomRs range gen)) The only IO action (newStdGen) is executed when tpdfs is called, but the infinite result list is lazily created when needed. This is possible because newStdGen uses split to create a new source of randomness exclusively for the tpdfs' function wich is not accessed anywhere else. tpdfs can be written more concisely as one of these tpdfs range = liftM (tpdfs' . randomRs range) newStdGen tpdfs range = return (tpdfs' . randomRs range) `ap` newStdGen tpdfs range = newStdGen >>= (randomRs range >>> tpdfs' >>> return) using either Control.Monad or Control.Arrow. I'm not sure your aproach is numerically correct. Let's assume range = (0, 1). The resulting number could be (0 + 0) `div` 2 = 0 (0 + 1) `div` 2 = 0 (1 + 0) `div` 2 = 0 (1 + 1) `div` 2 = 1 with equal probability. Is this what you want? Tillmann Rendel