[Haskell-cafe] infinite list of random elements

Matthew Brecknell haskell at brecknell.org
Tue Jul 31 21:53:05 EDT 2007


Chad Scherrer:
> Ok, that looks good, but what if I need some random values elsewhere
> in the program? This doesn't return a new generator (and it can't
> because you never get to the end of the list).

To fix that, just replace the call to getStdGen with a call to
newStdGen, as has already been suggested by Sebastian.

Internally, newStdGen uses "split" to produce an independent generator,
and also updates the global generator. Thus, repeated calls to newStdGen
all return independent generators.

So, bringing together the suggestions so far, we get this:

> import Random
> import Array
> 
> -- from Lauri Alanko
> randomElts rg xs = map (arr !) (randomRs bds rg)
>   where bds = (1, length xs)
>         arr = listArray bds xs
> 
> -- see discussion below
> inspect_stream = foldr (\x -> (seq x).(x:)) []
> 
> main = do
>   let foo g = drop 10000000 $ inspect_stream $ randomElts g [10,2,42::Int]
>   g1 <- newStdGen
>   g2 <- newStdGen
>   print $ take 10 $ foo g1
>   print $ take 10 $ foo g2

No space leaks, independent lazy infinite random sequences.

I was somewhat dismayed that I needed to write inspect_stream to make
the demonstration using drop work without a stack overflow. This is
because the current implementation of randomRs is quite lazy, making it
very easy to build up huge thunks which blow the stack if you don't
evaluate them from the inside out.

For most applications, where you inspect the random numbers in roughly
the same order as you extract them from the sequence, this wouldn't be a
problem. Are there real applications (as opposed to toy demonstrations)
where this wouldn't be the case? I don't know, but perhaps the question
of whether randomRs should be more strict warrants some discussion.



More information about the Haskell-Cafe mailing list