I have been working on random values recently and learned an important difference between
One functionality I recently added to client was ability of administrators to view, edit and create new people. Handler that processes incoming request to create a new person is shown below:
-- | Create new person postAdminApiAddPersonR :: Handler Value postAdminApiAddPersonR = do _ <- apiRequireAdmin msg <- requireJsonBody date <- runDB $ starDate _ <- raiseIfFailure $ validateAddPerson msg g <- liftIO newStdGen let person = evalRand (generatePersonM date msg) g pId <- runDB $ insert person returnJson (Entity pId person)
Basically it authenticates and authorizes user, validates the input and then calls
generatePersonM to generate a random character based on the user supplied parameters. However, the initial version was always creating identical clones, no matter how many times I tried calling it.
The problem was how I was handling random generator. Originally I had
g <- liftIO getStdGen, instead of
g <- liftIO newStdGen. Both will give you global random generator. The difference is that
newStdGen will also update it to a new value.
In a short lived program, where
getStdGen is called only one, the difference doesn’t matter. In long running program like this, where random generator is requested multiple times the difference is very noticeable. Every time I was calling
getStdGen, I was given the exact same value. And when I was using that exact same value in a pure function, I was getting exact same result as before. All this is explained in the documentation. I just weren’t paying enough attention to the little details.