[Haskell-beginners] Randomness woes

Gökhan San gsan at stillpsycho.net
Sun Jan 10 15:58:02 EST 2010


Erlend Hamberg <ehamberg at gmail.com> writes:

>   g <- getSplit
>   let genome' = evalRand (mutate genome) g
>
> Handling the random generator explicitly like this feels a bit ugly. Or is 
> this okay?

I was working on a very similar problem and I used 'split' of RandomGen
all the way down. It behaved well as far as I can tell, and if I recall
correctly, 'split' was faster than 'next' for StdGen.

So, I'd also appreciate any comment on the elegance issue myself. :-)

Though, I didn't quite get why you are explicitly calling 'evalRand'
instead of utilizing MonadRandom.

Here's an example:

> makePopulation :: (RandomGen g) => [(Genome, Fitness)] -> Rand g [Genome]
> makePopulation chms = do
>     g <- getSplit
>     return $ makePopulation' chms g []
>         where size = length chms
>               makePopulation' c g' a =
>                   if length a == size
>                      -- if we have ‘size’ members, we are done
>                      then a
>                      -- if not, find two new parents and append a child
>                      else makePopulation' c g' newPop
>                          where parent1  = evalRand (rouletteSelect chms) g'
>                                parent2  = evalRand (rouletteSelect chms) g'
>                                c1       = evalRand (reproduce (parent1, parent2) mutationRate) g'
>                                newPop   = c1:a

Here, you're generating both parents using the same random generator,
hence, parents are always identical. Here's a variation that works
within MonadRandom:

> makePopulation :: (RandomGen g) => [(Genome, Fitness)] -> Rand g [Genome]
> makePopulation chms = makePopulation' []
>     where size = length chms
>           makePopulation' a =
>               if length a == size
>               -- if we have ‘size’ members, we are done
>               then return a
>               -- if not, find two new parents and append a child
>               else do parent1 <- rouletteSelect chms
>                       parent2 <- rouletteSelect chms
>                       c1      <- reproduce (parent1, parent2) mutationRate
>                       let newPop = c1:a
>                       makePopulation' newPop

I didn't check for bugs in the algorithm but now both parents and the
offspring are generated independently, and resulting fitness values
won't be identical.

I think the idea is that you should be able to reduce the number of
'evalRand's in your module to one.

-- 

Gökhan San


More information about the Beginners mailing list