content: -- |
  -- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
  -- License    : BSD3
  -- Maintainer : ivan.perez@keera.co.uk
  --
  -- In this module, 'MSF's in a monad supporting random number generation (i.e.
  -- having the 'RandT' layer in its stack) can be run. Running means supplying
  -- an initial random number generator, where the update of the generator at
  -- every random number generation is already taken care of.
  --
  -- Under the hood, 'RandT' is basically just 'StateT', with the current random
  -- number generator as mutable state.
  module Control.Monad.Trans.MSF.Random
      ( runRandS
      , evalRandS
      , getRandomS
      , getRandomsS
      , getRandomRS
      , getRandomRS_
      , getRandomsRS
      , getRandomsRS_
      )
    where
  
  -- External imports
  import Control.Arrow        (arr, (>>>))
  import Control.Monad.Random (MonadRandom, RandT, Random, RandomGen, getRandom,
                               getRandomR, getRandomRs, getRandoms, runRandT)
  
  -- Internal imports
  import Control.Monad.Trans.MSF.State (StateT (..), runStateS_)
  import Data.MonadicStreamFunction    (MSF, arrM, constM, morphS)
  
  -- | Run an 'MSF' in the 'RandT' random number monad transformer by supplying
  -- an initial random generator. Updates the generator every step.
  runRandS :: (RandomGen g, Functor m, Monad m)
           => MSF (RandT g m) a b
           -> g -- ^ The initial random number generator.
           -> MSF m a (g, b)
  runRandS = runStateS_ . morphS (StateT . runRandT)
  
  -- | Evaluate an 'MSF' in the 'RandT' transformer, i.e. extract possibly random
  -- values by supplying an initial random generator. Updates the generator every
  -- step but discharges the generator.
  evalRandS :: (RandomGen g, Functor m, Monad m)
            => MSF (RandT g m) a b -> g -> MSF m a b
  evalRandS msf g = runRandS msf g >>> arr snd
  
  -- | Create a stream of random values.
  getRandomS :: (MonadRandom m, Random b) => MSF m a b
  getRandomS = constM getRandom
  
  -- | Create a stream of lists of random values.
  getRandomsS :: (MonadRandom m, Random b) => MSF m a [b]
  getRandomsS = constM getRandoms
  
  -- | Create a stream of random values in a given fixed range.
  getRandomRS :: (MonadRandom m, Random b) => (b, b) -> MSF m a b
  getRandomRS range = constM $ getRandomR range
  
  -- | Create a stream of random values in a given range, where the range is
  -- specified on every tick.
  getRandomRS_ :: (MonadRandom m, Random b) => MSF m (b, b) b
  getRandomRS_  = arrM getRandomR
  
  -- | Create a stream of lists of random values in a given fixed range.
  getRandomsRS :: (MonadRandom m, Random b) => (b, b) -> MSF m a [b]
  getRandomsRS range = constM $ getRandomRs range
  
  -- | Create a stream of lists of random values in a given range, where the
  -- range is specified on every tick.
  getRandomsRS_ :: (MonadRandom m, Random b) => MSF m (b, b) [b]
  getRandomsRS_ = arrM getRandomRs
  