{-# 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 = p Int
forall a. Random a => p a
forall (p :: * -> *) a. (ParRand p, Random a) => p a
rand 

-- | Trivial instance.
instance RandomGen g => SplittableState g where
  splitState :: g -> (g, g)
splitState = g -> (g, g)
forall g. RandomGen g => g -> (g, g)
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 :: forall a. Random a => StateT g p a
rand    = do 
               g <- StateT g p g
forall (m :: * -> *) s. Monad m => StateT s m s
S.get
	       let (x,g') = random g 
	       S.put g'
	       return x
  randInt :: StateT g p Int
randInt = do 
               g <- StateT g p g
forall (m :: * -> *) s. Monad m => StateT s m s
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 :: forall (fut :: * -> *) (p :: * -> *) a.
ParFuture fut p =>
(p a -> a) -> StateT StdGen p a -> IO a
runParRand p a -> a
runPar StateT StdGen p a
m = 
  do g <- IO StdGen
forall (m :: * -> *). MonadIO m => m StdGen
newStdGen
     evaluate (runPar (evalStateT m g))


-- | A convenience type for the most standard
type ParRandStd par a = StateT StdGen par a