{-# LANGUAGE FlexibleInstances, UndecidableInstances #-} -- | This module defines another Par-related class to capture the -- random number generation capability. -- -- The `rand` operation provides deterministic parallel random -- number generation from within a Par monad. -- -- Most likely one will simply use the `ParRand` the instance -- provided in this file, which is based on a state transformer -- carrying the random generator. module Control.Monad.Par.RNG ( ParRand(..), runParRand, ParRandStd ) where import System.Random import Control.Exception import Control.Monad.Par.Class import Control.Monad.Par.State import Control.Monad.Trans import Control.Monad.Trans.State.Strict as S -- | A `ParRand` monad is a Par monad with support for random number generation.. class ParRand p where rand :: Random a => p a -- This can be more efficient: randInt :: p Int randInt = rand -- | Trivial instance. instance RandomGen g => SplittableState g where splitState = split -- | The most straightforward way to get a `ParRand` monad: carry a -- RNG in a state transformer. instance (ParFuture fut p, RandomGen g) => ParRand (StateT g p) where rand = do g <- S.get let (x,g') = random g S.put g' return x randInt = do g <- S.get let (x,g') = next g S.put g' return x -- An alternative is for these operators to be standalone without a class: -- rand :: (ParFuture p fut, RandomGen g, Random a) => StateT g p a -- randInt :: (ParFuture p fut, RandomGen g) => StateT g p Int -- runParRand :: ParRand p => (p a -> a) -> p a -> IO a runParRand :: ParFuture fut p => (p a -> a) -> StateT StdGen p a -> IO a runParRand runPar m = do g <- newStdGen evaluate (runPar (evalStateT m g)) -- | A convenience type for the most standard type ParRandStd par a = StateT StdGen par a