[Haskell-beginners] Creating lists of random numbers

Daniel Fischer daniel.is.fischer at web.de
Thu Oct 21 09:21:14 EDT 2010


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



More information about the Beginners mailing list