@ 131018.10
current
module Monads.MRand
  ( MRand
  , eval, random, randomR, randoms, randomRs
  )
where

import qualified System.Random as R

-- | A random monad that works with any generator satisfying `RandomGen`.
newtype MRand g a = MRand (g -> (a, g))

instance R.RandomGen g => Monad (MRand g) where
  return a = MRand (\g -> (a, g))
  MRand m0 >>= f = MRand (\g -> let (a, g') = m0 g
                                    MRand m1 = f a
                                 in m1 g')

-- | Evaluate an instance of the `MRand` monad with a source of randomness.
eval :: R.RandomGen g => MRand g a -> g -> a
eval (MRand f) g = fst (f g)

-- | Provides a random value.
random :: (R.RandomGen g, R.Random a) => MRand g a
random = MRand R.random

-- | Provides a random value in a range.
randomR :: (R.RandomGen g, R.Random a)
           => (a, a) -- ^ An inclusive range [lo, hi].
           -> MRand g a
randomR r = MRand (R.randomR r)

-- | Provides an infinite list of random values.
randoms :: (R.RandomGen g, R.Random a) => MRand g [a]
randoms = MRand (\g -> let (g', g'') = R.split g in (R.randoms g', g''))

-- | Provides an infinite list of random values in a range.
randomRs :: (R.RandomGen g, R.Random a)
            => (a, a) -- ^ An inclusive range [lo, hi].
            -> MRand g [a]
randomRs r = MRand (\g -> let (g', g'') = R.split g in (R.randomRs r g', g''))

-- Demonstrates two infinite, independent sources of integers.
two :: R.RandomGen g => MRand g ([Int], [Int])
two = do
  xs <- randomRs (1, 10)
  ys <- randomRs (1, 10)
  return (xs, ys)

main = do
  g <- R.getStdGen
  let (xs, ys) = eval two g
  print $ take 10 xs
  print $ take 10 ys