##### Views

(Difference between revisions)

equivalent of
RandomGen
's
split
function:
```class (MonadRandom m) => MonadRandomSplittable m where
splitRandom :: m a -> m a

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 }

## 1 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)
(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)```

## 2 Laws

It is not clear to me exactly what laws
splitRandom
should satisfy, besides monadic variations of the "split laws" from the Haskell Library Report [1] 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)```

## 3 Why?

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