packages feed

rhine-1.1: src/FRP/Rhine/ClSF/Random.hs

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}

{- | Create 'ClSF's with randomness without 'IO'.
   Uses the @MonadRandom@ package.
   This module copies the API from @dunai@'s
   'Control.Monad.Trans.MSF.Random'.
-}
module FRP.Rhine.ClSF.Random (
  module FRP.Rhine.ClSF.Random,
  module X,
)
where

-- transformers
import Control.Monad.IO.Class

-- MonadRandom
import Control.Monad.Random

-- dunai
import Control.Monad.Trans.MSF.Except (performOnFirstSample)
import Control.Monad.Trans.MSF.Random as X hiding (evalRandS, getRandomRS, getRandomRS_, getRandomS, runRandS)
import qualified Control.Monad.Trans.MSF.Random as MSF

-- rhine
import FRP.Rhine.ClSF.Core
import FRP.Rhine.ClSF.Random.Util

-- * Generating random values from the 'RandT' transformer

-- | Generates random values, updating the generator on every step.
runRandS ::
  (RandomGen g, Monad m) =>
  ClSF (RandT g m) cl a b ->
  -- | The initial random seed
  g ->
  ClSF m cl a (g, b)
runRandS clsf = MSF.runRandS (morphS commuteReaderRand clsf)

-- | Updates the generator every step but discards the generator.
evalRandS ::
  (RandomGen g, Monad m) =>
  ClSF (RandT g m) cl a b ->
  g ->
  ClSF m cl a b
evalRandS clsf g = runRandS clsf g >>> arr snd

{- | Updates the generator every step but discards the value,
   only outputting the generator.
-}
execRandS ::
  (RandomGen g, Monad m) =>
  ClSF (RandT g m) cl a b ->
  g ->
  ClSF m cl a g
execRandS clsf g = runRandS clsf g >>> arr fst

-- | Evaluates the random computation by using the global random generator.
evalRandIOS ::
  (Monad m) =>
  ClSF (RandT StdGen m) cl a b ->
  IO (ClSF m cl a b)
evalRandIOS clsf = evalRandS clsf <$> newStdGen

-- | Evaluates the random computation by using the global random generator on the first tick.
evalRandIOS' ::
  (MonadIO m) =>
  ClSF (RandT StdGen m) cl a b ->
  ClSF m cl a b
evalRandIOS' = performOnFirstSample . liftIO . evalRandIOS

-- * Creating random behaviours

-- | Produce a random value at every tick.
getRandomS ::
  (MonadRandom m, Random a) =>
  Behaviour m time a
getRandomS = constMCl getRandom

{- | Produce a random value at every tick,
   within a range given per tick.
-}
getRandomRS ::
  (MonadRandom m, Random a) =>
  BehaviourF m time (a, a) a
getRandomRS = arrMCl getRandomR

{- | Produce a random value at every tick,
   within a range given once.
-}
getRandomRS_ ::
  (MonadRandom m, Random a) =>
  (a, a) ->
  Behaviour m time a
getRandomRS_ range = constMCl $ getRandomR range