Need help

D. Tweed tweed@compsci.bristol.ac.uk
Tue, 23 Jul 2002 16:46:37 +0100 (BST)


On Tue, 23 Jul 2002, Nick Name wrote:

> It's relatively simple.
> 
> The random number generator is a pure function, so it cannot be
> nondeterministic. So, you have a way to build this function with a seed,
> since the author wanted you to be able to do so, I could say for
> completeness, or reuse sake.
> 
> But what you want is nondeterminism. How can you get that? With I/O of
> course. So, apart from the fact I am not going to search the "getTime"
> function, but it's probable haskell has one, and apart from the fact
> that getTime is also nondeterministic, here's a program that prints a
> true random number. Since this program uses I/O, it's a monadic action. 

You shouldn't _need_ to be in the IO monad to get random numbers (although
if you choose to that can be a good choice). Clearly there's the need to
initialise the generator, but if you want `random' random numbers (as
opposed to a known sequence of random numbers for debugging) getting the
value of time via an unsafePerformIO is as good as anything else. From
then on, the pseudo-random number generator will deterministically produce
what are hopefully `acceptably random looking' numbers.

As I made some (frankly rather confused) contribution to the debate that
led to the current formulation of Random.hs, I'll have a go at explaining
the intended usage.

Supposing you wanted a program that generated a list of random names from
a preset list, then you could have

f :: [Int] -> [Name] -> [Name]
f xs names = map (\x->names!!x) xs

where you supply a (lazily generated) infinite list of random integers in
xs. This is good because by changing the initialisation of the function
generating the lazy list, you can get reliably __the same random list__
for debugging purposes. The problem comes if you've got, e.g., a need to
generate two random lists: a good solution is clearly something along the
lines of

g::[Int]->[Name]->[Name]->([Name],[Name])
g xs names1 names2 = (f ys names1,f zs names2)
   where (ys,zs) = `two statistically independent random list generated
                        from xs'

The problem is to find a convenient way to split up the original list for
passing to sub functions where not only are the pieces independent as
complete lists, but also that no matter what pattern of further splitting
the subfunctions use all pairs below are statistically independent. The
idea used in the Randoms library is to have an abstract data-type StdGen
which you can apply `randoms' to to get an infinite list of random numbers
and which you can (deterministically) `split' into two new StdGen's which
should give statistically independent sequences. With these you should get

(i) the ability to write programs by passing around either generators or
infinite lists, so that you can set them to produce the same results
each time for debugging purposes.

(ii) no need for the IO monad to infect functions purely because the need
random numbers.

I don't know the answer to the original posters question; however
Randoms.hs contains

primitive getRandomSeed :: IO Integer

which I believe you can use either to get the seed within the IO monad
directly or via unsafePerformIO if you don't want the IO monad around.

HTH, 

___cheers,_dave_________________________________________________________
www.cs.bris.ac.uk/~tweed/  |  `It's no good going home to practise
email:tweed@cs.bris.ac.uk  |   a Special Outdoor Song which Has To Be
work tel:(0117) 954-5250   |   Sung In The Snow' -- Winnie the Pooh