Hi all, I am having a problem with the implementation of a program (a genetic algorithm) which requires randomness in it.<br><br>It all hinges on the ability to generate something (in the example below an <span style="font-family: courier new,monospace;">
Int</span>), then provide a function to update it such that the prelude's
<span style="font-family: courier new,monospace;">iterate</span>
function (or an equivalent) may be used. In my program I require that
both the generation and the updating function contain randomness.<br><br>I have drafted a (simplified) example of my problem:
<br><br>This
code show a trivial case where randomness (and hence the IO monad) is
not used and the first 10 elements of the produced list are printed:
<br><br><span style="font-family: courier new,monospace;">aNum :: Int</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">aNum = 2</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">addTwo :: Int -> Int</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
addTwo = (+) 2</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">firstTen :: [Int]</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">firstTen = take 10 (iterate addTwo aNum)</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
main :: IO ()</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">main = do</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
print firstTen</span><br style="font-family: courier new,monospace;"><br>As required the program terminates printing:<br><span style="font-family: courier new,monospace;">[2,4,6,8,10,12,14,16,18,20]</span><br><br>Now
I present my 'conversion' of this trivial case where we both generate a
random number, and add a random amount to it upon each iteration. Again
we only wish to print the first 10:
<br><br><span style="font-family: courier new,monospace;">import System.Random</span><br style="font-family: courier new,monospace;"><br><span style="font-family: courier new,monospace;">-- Taken directly from function 'rollDice' in Haskell98 report
</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">randNum :: IO Int</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
randNum = getStdRandom (randomR (1, 6))</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">addRand :: Int -> IO Int</span>
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">addRand x = do</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> y <- randNum
</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> return (x + y)</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">firstTen :: IO [Int]</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">firstTen = do</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> infiniteNums <- iterateM addRand randNum</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> return (take 10 infiniteNums)
</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">main :: IO ()</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">main = do</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> tenNums <- firstTen</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> print tenNums</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
-- Monadic interpretation of prelude iterate definition</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">iterateM :: Monad m => (a -> m a) -> m a -> m [a]
</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">iterateM f xM = do</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">
x <- xM</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> mcons xM (iterateM f (f x))</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">-- Taken from prelude definition of sequence</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">mcons :: Monad m => m a -> m [a] -> m [a]
</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">mcons p q = p >>= \x -> q >>= \y -> return (x:y)<br><br><br></span>However this latter case gets stuck in an infinite loop, terminating on a stack overflow.
<br><br>My question asks why this is the case, when laziness should ensure only the first 10 cases need to be computed.<br><br>If anyone wishes to suggest another way entirely to approach this problem that would also be welcome!
<br><br>Many Thanks, <br><span><span>Dave</span></span>