# [Haskell-cafe] better way to do this?

Wed Oct 7 05:07:11 EDT 2009

On Tue, 2009-10-06 at 13:22 -0700, Michael P Mossey wrote:
> Duncan Coutts wrote:
>
> > So you end up with pure functions like:
> >
> > shuffle :: RandomGen g => g -> [x] -> [x]
>
> Thanks for the help, Duncan. I'm confused on one point. Don't you always need
> the new state of the generator back? So wouldn't this need to be:
>
> shuffle :: RandomGen g => g -> [x] -> (g,[x])

Yes if you want it back at the end.

This is actually an interesting case for split, which is another member
of the RandomGen class. Having the luxury to discard the tail of the
sequence relies on us being able to split the RNG first so that we don't
end up loosing the RNG completely.

Why might we want to be able to discard the tail? In the shuffle case
above we can actually do the shuffle lazily. If we use the right
algorithm we can use a single random number per element returned, and
only have to compute each random number when each element of the result
is demanded. But if we had to return the final state of the RNG then
that would force us to have used all the random numbers we might
eventually need, which would defeat the lazy shuffle.

> > Another approach is to hide the 'g' inside a monad. That's what
> >
> > shuffle :: [x] -> Rand [x]
>
> One tutorial mentions the class Gen in the Test.QuickCheck module. Is "Rand" a
> different class defined somewhere else?

with passing the RNG in and returning the new one at the end. It's
similar to QC's Gen monad, but not specialised to the task of generating
random elements of various types.

> > The tutorials above explain about the other random functions, for
> > getting values of different types (not just Int) and restricted ranges
> > of number etc.
> >
> > Of course at some point you want to seed the random number generator
> > with some initial genuinely random value (not like the 12345 we used
> > above). That is the only place in your random-handling code that needs
> > to do IO. All the rest of it can be pure.
>
> What function gives you that initial random seed? (Grabs it from the system clock?)

System.Random doesn't have an explicit "initialise from the system"
action. It has a global StdGen that is always available and gets
initialised once from the system.

To get a new, independent StdGen use

newStdGen :: IO StdGen

which works just by applying 'split' to the global StdGen.

Duncan