[Haskell-cafe] Printing a random list

Ronald Guida oddron at gmail.com
Sun Jun 8 20:25:41 EDT 2008


Bryan Catanzaro wrote:
> However, when I ran my random list generator, the interpreter had a stack
> overflow.  Here's my code again:
> ---
> module Main
>    where
>      import IO
>      import Random
>
>      randomList :: Random a => a -> a-> [IO a]
>      randomList lbound ubound = randomRIO(lbound, ubound) : randomList
> lbound ubound
>
>
>      main = do
>        myRandomList <- sequence(randomList (0::Int) 255)
>        putStrLn(show(take 10 myRandomList))
> ---
>
> It seems that this code somehow tries to evaluate every element of the
> infinite list defined by randomList.

You are correct.

> Can you tell me why it is not lazily evaluating this list?

Whenever you use IO, there is a baton being passed along behind the
scenes.  The baton is called "RealWorld#" and it represents the fact
that interactions with global state and the outside world have to be
serialized.

In particular, whenever you use the global random number generator, a
global state variable has to be updated.  This has to be serialized,
thus the baton has to be passed along from one action to the next.

When you "sequence" a list of IO actions, you are effectively sending
the baton along that list, and you don't get it back until the end of
the list is reached.  Your code is sending the baton into an infinite
list of actions, never to be returned.

>  I can get around this by changing main to do this
> instead:
>
> ---
>      main = do
>        myRandomList <- sequence(take 10 (randomList (0::Int) 255))
>        putStrLn(show(myRandomList))
> ---

Now you are sending the baton into a list of only 10 actions.  The
baton comes back, and the program goes on.

If you don't know in advance how many random numbers you need, and if
you are satisfied with the global random number generator, then Don
Stewart's solution is a better approach.

Don Stewart wrote:
>   main = do
>         g <- newStdGen
>         print (take 10 (randomRs (0,255) g :: [Int]))

If you want to be able to reproduce the same sequence of random
numbers, for example for testing and debugging purposes, then you can
use mkStdGen to create your own random number generator, independent
of the global one.  The catch is that you will have to thread the
state of the random number generator through your code.  Once you
learn about monads (if you haven't already), you'll recognize that you
can use the State monad for your random number generator.


More information about the Haskell-Cafe mailing list