
I just thought about something: basically all these APIs provides a "IO
[a]" (where a is a randomly generable type) function.
Is there a problem with the approach that is to rely on lazy evaluation to
pass to pure code (either explicitely or through State) the infinite list
generated in IO and consume its head each time we need a random value?
Because there is no issue such as resource holding, like in the case of
file reading and enumerators, which would make lazy IO a not so good
approach...
2012/2/9 Aleksey Khudyakov
On 09.02.2012 17:28, Jerzy Karczmarczuk wrote:
Aleksey Khudyakov:
On 09.02.2012 15:32, Jerzy Karczmarczuk wrote:
1. Mersenne Twister, AND congruential generators AND the Marsaglia stuff, all use some kind of "seed", all are stateful. There are no miracles. Just look the agressive monadization, the form of defaultSeed, etc. within MWC.hs, before saying that this generator doesn't rely on some global state.
I think you are missing the point here. Surely all PRNG carry some state around. But both StdGen and mwc-random (and likely many others) allow to have many generators at once (for use in different threads)
This is irrelevant. I believe that there is a misunderstanding in terminology. When I say "global state" it means not a local variable in some function. You seem to say "one object per programme". This is confirmed by:
mersenne-random is just wrapper around vastly impure library (as
documentation says) and allows only one genrator per program. This is why I said it uses *global* state
In any case, the seed changes after each generation, and
must be stored somewhere.
No. It doesn't and cannot
data StdGen = StdGen Int32 Int32
If generator state is stored in IORef it's not possible to implement `next :: g → (Int,g)'. To do something useful with it one have to go to IO monad but we can't. So state have to be copied.
We can't WHAT? Look, all data that change or are created MUST be stored somewhere, don't say dubious things. Your next function is a "threading generator", which makes another StdGen, OK, but this is not a "copy". This is a creation of a new seed. When I spoke about IORefs, I thought about the global generator, which USES the l'Ecuyer stuff, newStdGen and its friends.
The threading becomes implicit. Try, say r=newStdGen r >>= return . next
and you will see, it works, and you don't keep explicitly your seed. From the efficiency point of view all this is comparable. With IOrefs you do not "pollute" the memory which has to be garbage-collected, but its administration is heavier than the standard heap operations. StdGen with l'Ecuyer two-number seed, or some 600 of the Mersenne, I don't see a conceptual difference. The Marsaglia generator has a global seed quite voluminous as well.
I didn't quite understand you
In order to implement RandomGen one have to implement `next' function
next :: g → (Int,g)
Lets assume that g stores internal generator state (In case of NWC256 it's 258 Word32s). We cannot modify it in place. Someone may hold this g and changing it behind the scenes will violate referential transparence. We have to create new array and this is expensive.
There still way out as Duncan Coutts pointed out. We may generate stream of random numbers in lazy ST monad and use them as random generator.
No idea what do you mean. In the Random library you will find the
generators using IORefs, AND the class Random, with the member random (or randomR, etc.) and you may write getStdRandom random getStdRandom random ... as you wish, getting different results. What's wrong with that?
Nothing. I was talking about problems with `next' function. One always can use IORefs to create global generator but that's irrelevant
______________________________**_________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/**mailman/listinfo/haskell-cafehttp://www.haskell.org/mailman/listinfo/haskell-cafe