Difference between revisions of "New monads/MonadRandomSplittable"

From HaskellWiki
Jump to navigation Jump to search
m (heading/ link)
(Add links)
Line 11: Line 11:
 
</haskell>
 
</haskell>
   
MonadRandomSplittable can then be derived for Rand by GHC:
+
MonadRandomSplittable can then be derived for Rand by [[GHC]]:
 
<haskell>
 
<haskell>
 
newtype Rand g a = Rand { unRand :: RandomT g Identity a }
 
newtype Rand g a = Rand { unRand :: RandomT g Identity a }
Line 45: Line 45:
 
== Laws ==
 
== Laws ==
   
It is not clear to me exactly what laws <hask>splitRandom</hask> should satisfy.
+
It is not clear to me exactly what [[Monad laws|laws]] <hask>splitRandom</hask> should satisfy.
   
 
For all terminating <hask>ma</hask> and <hask>mb</hask>, it should hold that
 
For all terminating <hask>ma</hask> and <hask>mb</hask>, it should hold that
Line 52: Line 52:
 
</haskell>
 
</haskell>
   
For monad transformers, it would also be nice if
+
For [[monad transformer]]s, it would also be nice if
 
<haskell>
 
<haskell>
 
splitRandom undefined === splitRandom (return ()) >> lift undefined
 
splitRandom undefined === splitRandom (return ()) >> lift undefined

Revision as of 19:53, 17 November 2006


When using New monads/MonadRandom, one may also want to use a MonadRandom equivalent of RandomGen's split function:

class (MonadRandom m) => MonadRandomSplittable m where
    splitRandom :: m a -> m a

instance (Monad m, RandomGen g) => MonadRandomSplittable (RandomT g m) where
    splitRandom ma  = (RandomT . liftState) split >>= lift . evalRandomT ma

MonadRandomSplittable can then be derived for Rand by GHC:

newtype Rand g a = Rand { unRand :: RandomT g Identity a }
    deriving (Functor, Monad, MonadRandom, MonadRandomSplittable)

Example of usage

test   :: Rand StdGen [Bool] -> (Int, [Bool], Int)
test ma = evalRand (liftM3 (,,) (getRandomR (0,99)) ma (getRandomR (0,99)))
                (mkStdGen 0)

Then

*MonadRandom> test (replicateM 0 getRandom)
(45,[],55)
*MonadRandom> test (replicateM 2 getRandom)
(45,[True,True],0)

*MonadRandom> test (splitRandom $ replicateM 0 getRandom)
(45,[],16)
*MonadRandom> test (splitRandom $ replicateM 2 getRandom)
(45,[False,True],16)

*MonadRandom> case test undefined of (a,_,c) -> (a,c)
*** Exception: Prelude.undefined
*MonadRandom> case test (splitRandom undefined) of (a,_,c) -> (a,c)
(45,16)

Laws

It is not clear to me exactly what laws splitRandom should satisfy.

For all terminating ma and mb, it should hold that

  liftM3 (\a _ c -> (a,c)) getRandom ma getRandom === liftM3 (\a _ c -> (a,c)) getRandom mb getRandom

For monad transformers, it would also be nice if

splitRandom undefined === splitRandom (return ()) >> lift undefined

For example,

>runIdentity $ runRandomT (splitRandom (return ()) >> lift undefined >> return ()) (mkStdGen 0)
((),40014 2147483398)
>runIdentity $ runRandomT (splitRandom undefined >> return ()) (mkStdGen 0)
((),40014 2147483398)

But

>runRandomT (splitRandom (return ()) >> lift undefined >> return ()) (mkStdGen 0)
*** Exception: Prelude.undefined
>runRandomT (splitRandom undefined >> return ()) (mkStdGen 0)
*** Exception: Prelude.undefined

I have no idea how to express this idea for monads that aren't transformers though. But for Rand it means that:

>runRand (splitRandom undefined >> return ()) (mkStdGen 0)
((),40014 2147483398)

Why?

In replicateM 100 (splitRandom expensiveAction) There are no RNG-dependencies between the different expensiveActions, so they may be computed in parallel.