[Haskell-cafe] Help with IO and randomR

Bryan Burgers bryan.burgers at gmail.com
Mon Jul 16 08:31:03 EDT 2007

On 7/16/07, Niko Korhonen <niko.korhonen at gmail.com> wrote:
> I'm writing some code to generate a dither (=noise) signal. I'm trying
> to generate an infinite series of noise with triangular distribution but
> my code hangs into an infinite loop. The problem is that I'm not very
> good with Haskell IO yet and I can't figure out how to write this piece
> of IO code without it looping infinitely.
> 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)
>   return (r : rest)
> Caller site:
> do
>   nums <- tpdfs (2, 12)
>   let ns = take 7 nums
> Niko

I did not look at it long enough to tell you why there is an infinite
loop. However, think about it on a high level with me.

You want a stream of these random numbers (I'm not sure what a
triangular distribution is, but that's okay). To get one of these, you
take two random numbers and perform a combination function (\x y -> (x
+ y) `div` 2 ) on them.

So you can lift this from one random numbers to a stream of random
numbers if you have have two streams of random numbers instead of just
two random numbers. zipWith is the function that brings us from one
number to a stream of numbers.

tpdfs range = do
   g <- newStdGen   -- get a random generator
   (g1, g2) <- return $ split g   -- make two random generators out of it
   return $ zipWith combine (randomRs range g1) (randomRs range g2)
-- get two streams of random numbers, and combine them elementwise.

combine x y = (x + y) `div` 2

Uh, I know that's a very poor explanation, but hopefully it gives you
an alternate way to look at the problem.

More information about the Haskell-Cafe mailing list