# [Haskell-cafe] Re: Help with IO and randomR

Niko Korhonen niko.korhonen at gmail.com
Tue Jul 17 02:16:14 EDT 2007

```Bryan Burgers wrote:
> 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.

Yes, precisely. Triangular distribution is a probability distribution
that is equivalent to two rolls of dice. This means that the numbers at
the middle of the range are much more likely to pop up than numbers at
the edge of the range. It is quite close to gaussian distribution.

I'm toying around with a signal processing toolkit in Haskell. The noise
I'm trying to generate here is needed for a process called dithering, in
which some noise is added to a quantized signal in order to improve it's
accuracy. But not just any kind of noise will do for this purpose. The
best noise for dithering is noise with triangular or gaussian
probability distribution, instead of white noise which has equal
probability distribution.

But, like you said, that's not really important for the purposes of this
discussion. What is is that we take a bunch of random numbers, perform
some mathematical operation on them in order to introduce some
statistical properties to the series and return the processed series.

There are several different probability distribution functions,
triangular being one of them. Triangular distribution requires two
random numbers to generate one, and some functions require more than that.

> 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

So, moving on to the next question, how well do you think this solution
would scale if we would need n random numbers to generate one?

Niko

```