[Haskell-cafe] "safe" way to use Rand?

Michael Mossey mpm at alumni.caltech.edu
Mon Oct 12 09:23:03 EDT 2009

I'm looking at Control.Monad.Random which provides the Rand monad. I would 
like to know how to use this for generating multiple infinite series, while 
trusting that the implementation never uses "split" behind the scenes.

(Note: I'm on Windows XP, and there appears to be a bug in getStdGen. It 
does NOT return an arbitrary generator, but rather the same one every time 
I run the program. However, newStdGen DOES return an arbitrary generator. 
So I'm using that, even though I know it accesses split behind the scenes. 
My thinking is that this only happens once so it is okay.)

For example, is this code split-free?

simple :: Rand StdGen [Int]
simple = getRandomRs (0::Int, 10)

main1 = do
    gen <- newStdGen
    let answer = (flip evalRand) gen $ do
               xs <- simple
               ys <- simple
               return $ (take 5 xs) ++ (take 3 ys)
    print answer

Then, to elaborate on my specific problem, I need to create special types 
of infinite series. For example, I might need to create one that looks like 

0 0 5 0 0 0 2 0 0 0 0 0 5 0 9 0 0 8 ...

The pattern here is that there is some random number of zeros followed by a 
single non-zero value, followed again by a random number of zeros, etc. 

This is one way to implement this. Does all look well here?

makeSeries :: [Int] -> [a] -> a -> [a]
makeSeries (i:is) (f:fs) zero = replicate i zero ++ [f]
                                 ++ makeSeries is fs zero

lessSimple :: Rand StdGen [Int]
lessSimple = do
   counts <- getRandomRs (1::Int  , 5  )
   values <- getRandomRs (1::Int  , 9  )
   return $ makeSeries counts values 0

main2 = do
    gen <- newStdGen
    let answer = evalRand lessSimple gen
    print . take 20 $ answer

We could even have several of these series zipped together. Is this split-free?

main3 = do
   gen <- newStdGen
   let fs = (flip evalRand) gen $ do
              s1 <- lessSimple
              s2 <- lessSimple
              return $ zip s1 s2
   print . take 20 $ fs

More information about the Haskell-Cafe mailing list