|
|
>> You write a function that takes a PRNG state and returns a random number
>> and a new PRNG state.
>
> Where do you store this state, given that you can't assign it to anything?
It's not so hard.
get_random :: Seed -> (Int, Seed)
foo :: Seed -> (Int, Seed)
foo s0 =
let
(x1,s1) = get_random s0
(x2,s2) = get_random s1
(x3,s3) = get_random s2
in ((x1 + x2 + x3) `div` 3, s3)
bar :: Seed -> ([Int], Seed)
bar s0 =
let
(y1,s1) = foo s0
(y2,s2) = foo s1
(y3,s3) = foo s2
in ([y1, y2, y3], s3)
Here "foo" grabs three random numbers and returns their arithmetic mean.
(And also returns the final PRNG seed, in case anybody else wants it.)
Basically you create a new variable for each version of the seed value.
(Similarly, "bar" calls "foo" three times to generate three (more
uniformly distributed) random numbers and returns them in a list - along
with the new seed.)
> But then the calling code would have to keep that seed somewhere. This
> can be a real burden if the same RNG stream would need to be used in
> different parts of the code.
Yes. This does quickly become tedious if you need random numbers all
over the place. In principle each function that uses it must take an
initial seed value, and return a new seed value as part of its result.
And the callers must remember to use the correct version of the state
each time.
(E.g., imagine if I make a typo and foo actually returns s0 instead of
s3. Now the "random" number generator appears to always return the same
result!)
But basically, it works.
You can improve it by using a state monad. This basically means that the
seed is invisibly passed from place to place automatically (and you
can't accidentally use the wrong seed by mistake).
Alternatively, you can go down the mutable state road. On the face of
it, this would still require you to pass around a reference to the
mutable state, because Haskell doesn't have mutable global variables. So
some hacking is required there.
Post a reply to this message
|
|