
Erlend - see below... Erlend Hamberg wrote:
... I have two concerns about my architecture. The first one is that I have several “layers” of randomness: The main function will call makePopulation which in turn will call rouletteSelect and reproduce. The latter will then call mutate, which also involves randomness. As can be seen above, I have rewritten mutate to take a list of booleans so that I can use getRandomRs in reproduce instead of having to have yet another layer of
g <- getSplit let genome' = evalRand (mutate genome) g
Handling the random generator explicitly like this feels a bit ugly. Or is this okay?
If you replace the code above with just mutate genome then it will pass the random number generator 'through' mutate and on completion the RNG in the calling context will be changed to what 'mutate' returned. Since you're not using multiple threads, this should be correct for your application, but it's not quite equivalent to your code, because you're not actually splitting the RNG. If you really need to split it, you could write yourself a helper function like this: splitting :: RandomGen g => Rand g a -> Rand g a splitting code = do g <- getSplit return $ evalRand code g Then say splitting $ mutate genome
Calling getSplit and then evalRand recursively is what I do in makePopulation, to make a new population. I would greatly appreciate comments on how this “should” be done. I realise that I could just get a list of random numbers in makePopulation and then use this as a source of randomness for the called functions, but I fear that this would just lead to inelegant code managing (chunks of) this list.
Gokhan San answered this better than I was going to. Steve