
On Thursday 21 October 2010 14:58:45, Tom Hobbs wrote:
Hi all,
I'm trying to create a list of random integers (either 0s or 1s). I've got one way to work, but I'm trying to use replicate to replace this implementation but it's not going well. Can anyone help, please?
Here's the version I want to replace;
ugly :: Int -> [Int] ugly 0 = [] ugly s = ugly (s-1) ++ [ran] where ran = unsafePerformIO (randomRIO (0,1)) :: Int
This one works as expected.
Here's the broken version;
broken :: Int -> [Int] broken s = replicate s ran where ran = unsafePerformIO (randomRIO (0,1)) :: Int
The problem with broken is that "ran" seems to be evaluated once and then replicated, so my list contains the same random number s times.
Right, ran is just a plain Int, it doesn't need to be evaluated more than once. You could try stillUgly :: Int -> [Int] stillUgly n = replicate n (f ()) where {-# NOINLINE f #-} f () = unsafePerformIO (randomRIO (0,1)) but you shouldn't.
I'd like it to be re-evaluated with each replication.
Also, I've heard of the dangers of using unsafePerformIO. Can anyone suggest a different way to generate random numbers?
A) pass the generator explicitly ranList :: StdGen -> Int -> [Int] ranList sg n = take n $ randomRs (0,1) sg and then, if you must, B) bearable :: Int -> [Int] bearable n = unsafePerformIO $ do sg <- getStdGen return $ ranList sg n but really, pass the generator. If that's too inconvenient, use MonadRandom (I've forgotten the name of the package, search hackage).
(Finally, a question that doesn't involve serialisation!)
Cheers,
Tom