Reputation: 3
When running genRandTupe
I continuously get the same random numbers, however when running genrandList
with gen
as the argument i get a new set of numbers every time. How would I solve this? Why doesn't g = newStdGen
generate a new random number?
import System.Random
import System.IO.Unsafe
type RandTupe = (Int,Int)
genRandTupe :: IO RandTupe
genRandTupe = let [a,b] = genrandList g in return (a,b) where g = newStdGen
genrandList gen = let g = unsafePerformIO gen in take 2 (randomRs (1, 20) g)
gen = newStdGen
Upvotes: 0
Views: 373
Reputation: 120711
genRandTupe
is a constant applicative form. That means any local variables in its let
or where
blocks are memoised. Usually quite a convenient feat!
In your case, it means that the list [a,b]
is only computed once in your whole program. The way it is computed is actually illegal (don't use unsafePerformIO
!), but it doesn't really matter because it only happens once anyway. Wrapping this constant tuple then into IO
with return
is actually completely superfluent, you could as well have written
genRandTupe' :: RandTupe
genRandTupe' = let [a,b] = genrandList g in (a,b)
where g = newStdGen
OTOH, when you evaluate genrandList gen
(not a CAF) in multiple separate places, the result will not necessarily be stored. Instead, that function is calculated anew, using unsafePerformIO
to unsafely modify the global state (or maybe not... the compiler is actually free to optimise this away since, you know, genRandList
is supposedly a pure function...) and therefore yield a different result each time.
The correct thing, of course, is to stay the heck away from unsafePerformIO
. There's actually no need at all to do IO in genRandList
, since it already accepts a random generator... just bind that generator out from IO before passing it:
genRandTupe'' :: IO RandTupe
genRandTupe'' = do
g <- newStdGen
let [a,b] = genrandList g
return (a,b)
randListFrom :: RandomGen g => g -> [Int]
randListFrom g = take 2 (randomRs (1, 20) g)
Note that, because the let [a,b] = ...
now is in a do
block, it's now in the IO
monad, decoupled from the CAF closure of genRandTupe''
.
Upvotes: 5