I want to have a function that return different stdGen
in each call without IO.
I've tried to use unsafePerformIO
, as the following code.
import System.IO.Unsafe
import System.Random
myStdGen :: StdGen
myStdGen = unsafePerformIO getStdGen
But when I try to call myStdGen
in ghci, I always get the same value. Have I abused unsafePerformIO
? Or is there any other ways to reach my goal?
EDIT Sorry, I think I should describe my question more precisely.
Actually, I'm implementing a variation of the treap data strutcure, which needs a special 'merge' operation. It relies on some randomness to guarentee amortized O(log n) expected time complexity.
I've tried to use a pair like (Tree, StdGen)
to keep the random generator for each treap. When inserting a new data to the treap, I would use random
to give random value to the new node, and then update my generator. But I've encountered a problem. I have a function called empty
which will return an empty treap, and I used the function myStdGen
above to get the random generator for this treap. However, if I have two empty treap, their StdGen
would be the same. So after I inserted a data to both treap and when I want to merge them, their random value would be the same, too. Therefore, I lost the randomness which I relies on.
That's why I would like to have a somehow "global" random generator, which yields different StdGen
for each call, so that each empty treap could have different StdGen
.
This is not a good use of
unsafePerformIO
.The reason you see the same number repeatedly in GHCi is that GHCi itself does not know that the value is impure, and so remembers the value from the last time you called it. You can type IO commands into the top level of GHCi, so you would expect to see a different value if you just type
getStdGen
. However, this won't work either, due to an obscure part of the way GHCi works involving not reverting top-level expressions. You can turn this of with:set +r
:Note that your impure function pretending to be pure will still not work.
You really do not want to go down this route.
unsafePerformIO
is not supposed to be used this way, and nor is it a good idea at all. There are ways to get what you wanted (likeunsafePerformIO randomIO :: Int
) but they will not lead you to good things. Instead you should be doing calculations based on random numbers inside a random monad, and running that in the IO monad.Update
I see from your updatee why you wanted this in the first place.
There are many interesting thoughts on the problem of randomness within otherwise referentially transparent functions in this answer.
Despite the fact that some people advocate the use of
unsafePerformIO
in this case, it is still a bad idea for a number of reasons which are outlined in various parts of that page. In the end, if a function depends on a source of randomness it is best for that to be specified in it's type, and the easiest way to do that is put it in a random monad. This is still a pure function, just one that takes a generator when it is called. You can provide this generator by asking for a random one in the mainIO
routine.A good example of how to use the random monad can be found here.