Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to figure out `random` function in Haskell

Tags:

random

haskell

I just learned about random function.

To my understanding, random function takes a value of type which is an instance of RandomGen and returns a random value whose value we can specify. On the other hand, mksdGen takes an Int and generates a random generator which random function needs.

I was trying to generate random Bool values. In order to do that, I made a function randomBool.

randomBool :: Int -> Bool
randomBool = fst . random . mkStdGen

Then I found a lot more Trues than Falses with small numbers. And I was curious about it and checked as following

> length $ takeWhile randomBool [1..]
53667

I think this means that for the first 53667 positive integers, random . mkStdGen returns True, which do not seem to be very random to me. Is it very normal? Or am I doing something wrong that make True happen more easily?

like image 635
Tengu Avatar asked Jun 25 '13 03:06

Tengu


1 Answers

Informally, when you call mkStdGen with seeds that are close together you will get two 'similar' generators. In your example you're actually creating new generators for each seed supplied, and since those seeds are 1, 2, 3, etc., they'll yield similar streams.

When you call random with a generator, you actually get back a new generator in the second element of the pair:

Prelude System.Random> random (mkStdGen 100) :: (Bool, StdGen)
(True,4041414 40692)

So a good idea is to use this provided generator for your next call to random. I.e.,

Prelude System.Random> let (i, gen0) = random (mkStdGen 100) :: (Bool, StdGen)
Prelude System.Random> let (j, gen1) = random gen0           :: (Bool, StdGen)
Prelude System.Random> let (k, gen2) = random gen1           :: (Bool, StdGen)
Prelude System.Random> (i, j, k)
(True, False, False)

So to make a bunch of random values, you want to pass the generator as state. You can set this up manually via a State monad or something, or just use the randoms function, which handles passing the generator state for you:

Prelude System.Random> take 10 $ randoms (mkStdGen 100) :: [Bool]
[True,False,False,False,False,True,True,False,False,True]

If you don't particularly care about being in IO (it happens) you can use randomIO:

Prelude System.Random> import Control.Monad
Prelude System.Random Control.Monad> replicateM 10 randomIO :: IO [Bool]
[True,True,False,True,True,False,False,False,True,True]

This section of LYAH might be a useful read.

like image 54
jtobin Avatar answered Oct 13 '22 04:10

jtobin