{-# 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 qualified Control.Monad.Trans.MSF.Random as MSF
import Control.Monad.Trans.MSF.Random as X hiding (runRandS, evalRandS, getRandomS, getRandomRS, getRandomRS_)

-- 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
  -> g -- ^ The initial random seed
  -> ClSF          m  cl a (g, b)
runRandS :: forall g (m :: Type -> Type) cl a b.
(RandomGen g, Monad m) =>
ClSF (RandT g m) cl a b -> g -> ClSF m cl a (g, b)
runRandS ClSF (RandT g m) cl a b
clsf g
g = forall g (m :: Type -> Type) a b.
(RandomGen g, Functor m, Monad m) =>
MSF (RandT g m) a b -> g -> MSF m a (g, b)
MSF.runRandS (forall (m2 :: Type -> Type) (m1 :: Type -> Type) a b.
(Monad m2, Monad m1) =>
(forall c. m1 c -> m2 c) -> MSF m1 a b -> MSF m2 a b
morphS forall r g (m :: Type -> Type) a.
ReaderT r (RandT g m) a -> RandT g (ReaderT r m) a
commuteReaderRand ClSF (RandT g m) cl a b
clsf) g
g

-- | 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 :: forall g (m :: Type -> Type) cl a b.
(RandomGen g, Monad m) =>
ClSF (RandT g m) cl a b -> g -> ClSF m cl a b
evalRandS ClSF (RandT g m) cl a b
clsf g
g = forall g (m :: Type -> Type) cl a b.
(RandomGen g, Monad m) =>
ClSF (RandT g m) cl a b -> g -> ClSF m cl a (g, b)
runRandS ClSF (RandT g m) cl a b
clsf g
g forall {k} (cat :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> forall (a :: Type -> Type -> Type) b c.
Arrow a =>
(b -> c) -> a b c
arr forall a b. (a, b) -> b
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 :: forall g (m :: Type -> Type) cl a b.
(RandomGen g, Monad m) =>
ClSF (RandT g m) cl a b -> g -> ClSF m cl a g
execRandS ClSF (RandT g m) cl a b
clsf g
g = forall g (m :: Type -> Type) cl a b.
(RandomGen g, Monad m) =>
ClSF (RandT g m) cl a b -> g -> ClSF m cl a (g, b)
runRandS ClSF (RandT g m) cl a b
clsf g
g forall {k} (cat :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> forall (a :: Type -> Type -> Type) b c.
Arrow a =>
(b -> c) -> a b c
arr forall a b. (a, b) -> a
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 :: forall (m :: Type -> Type) cl a b.
Monad m =>
ClSF (RandT StdGen m) cl a b -> IO (ClSF m cl a b)
evalRandIOS ClSF (RandT StdGen m) cl a b
clsf = do
  StdGen
g <- forall (m :: Type -> Type). MonadIO m => m StdGen
newStdGen
  forall (m :: Type -> Type) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall g (m :: Type -> Type) cl a b.
(RandomGen g, Monad m) =>
ClSF (RandT g m) cl a b -> g -> ClSF m cl a b
evalRandS ClSF (RandT StdGen m) cl a b
clsf StdGen
g

-- | 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' :: forall (m :: Type -> Type) cl a b.
MonadIO m =>
ClSF (RandT StdGen m) cl a b -> ClSF m cl a b
evalRandIOS' = forall (m :: Type -> Type) a b.
Monad m =>
m (MSF m a b) -> MSF m a b
performOnFirstSample forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: Type -> Type) cl a b.
Monad m =>
ClSF (RandT StdGen m) cl a b -> IO (ClSF m cl a b)
evalRandIOS

-- * Creating random behaviours

-- | Produce a random value at every tick.
getRandomS
  :: (MonadRandom m, Random a)
  => Behaviour m time a
getRandomS :: forall (m :: Type -> Type) a time.
(MonadRandom m, Random a) =>
Behaviour m time a
getRandomS = forall (m :: Type -> Type) b cl a. Monad m => m b -> ClSF m cl a b
constMCl forall (m :: Type -> Type) a. (MonadRandom m, Random a) => m a
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 :: forall (m :: Type -> Type) a time.
(MonadRandom m, Random a) =>
BehaviourF m time (a, a) a
getRandomRS = forall (m :: Type -> Type) a b cl.
Monad m =>
(a -> m b) -> ClSF m cl a b
arrMCl forall (m :: Type -> Type) a.
(MonadRandom m, Random a) =>
(a, a) -> m a
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_ :: forall (m :: Type -> Type) a time.
(MonadRandom m, Random a) =>
(a, a) -> Behaviour m time a
getRandomRS_ (a, a)
range = forall (m :: Type -> Type) b cl a. Monad m => m b -> ClSF m cl a b
constMCl forall a b. (a -> b) -> a -> b
$ forall (m :: Type -> Type) a.
(MonadRandom m, Random a) =>
(a, a) -> m a
getRandomR (a, a)
range