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

{- | Create 'ClSF's with randomness without 'IO'.
   Uses the @MonadRandom@ package.
   This module copies the API from @automaton@'s
   'Data.Automaton.Trans.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

-- automaton
import Data.Automaton.Trans.Except (performOnFirstSample)
import Data.Automaton.Trans.Random as X hiding (evalRandS, getRandomRS, getRandomRS_, getRandomS, runRandS)
import Data.Automaton.Trans.Random qualified as Automaton

-- 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 :: 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 = Automaton (RandT g (ReaderT (TimeInfo cl) m)) a b
-> g -> Automaton (ReaderT (TimeInfo cl) m) a (g, b)
forall g (m :: Type -> Type) a b.
(RandomGen g, Functor m, Monad m) =>
Automaton (RandT g m) a b -> g -> Automaton m a (g, b)
Automaton.runRandS ((forall x.
 ReaderT (TimeInfo cl) (RandT g m) x
 -> RandT g (ReaderT (TimeInfo cl) m) x)
-> ClSF (RandT g m) cl a b
-> Automaton (RandT g (ReaderT (TimeInfo cl) m)) a b
forall (m :: Type -> Type) (n :: Type -> Type) a b.
Monad m =>
(forall x. m x -> n x) -> Automaton m a b -> Automaton n a b
hoistS ReaderT (TimeInfo cl) (RandT g m) x
-> RandT g (ReaderT (TimeInfo cl) m) x
forall x.
ReaderT (TimeInfo cl) (RandT g m) x
-> RandT g (ReaderT (TimeInfo cl) m) x
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)

-- | 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 = ClSF (RandT g m) cl a b -> g -> ClSF m cl a (g, 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 (g, b)
runRandS ClSF (RandT g m) cl a b
clsf g
g ClSF m cl a (g, b)
-> Automaton (ReaderT (TimeInfo cl) m) (g, b) b
-> Automaton (ReaderT (TimeInfo cl) m) a b
forall {k} (cat :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> ((g, b) -> b) -> Automaton (ReaderT (TimeInfo cl) m) (g, b) b
forall b c. (b -> c) -> Automaton (ReaderT (TimeInfo cl) m) b c
forall (a :: Type -> Type -> Type) b c.
Arrow a =>
(b -> c) -> a b c
arr (g, b) -> b
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 = ClSF (RandT g m) cl a b -> g -> ClSF m cl a (g, 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 (g, b)
runRandS ClSF (RandT g m) cl a b
clsf g
g ClSF m cl a (g, b)
-> Automaton (ReaderT (TimeInfo cl) m) (g, b) g
-> Automaton (ReaderT (TimeInfo cl) m) a g
forall {k} (cat :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> ((g, b) -> g) -> Automaton (ReaderT (TimeInfo cl) m) (g, b) g
forall b c. (b -> c) -> Automaton (ReaderT (TimeInfo cl) m) b c
forall (a :: Type -> Type -> Type) b c.
Arrow a =>
(b -> c) -> a b c
arr (g, b) -> g
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 = ClSF (RandT StdGen m) cl a b -> StdGen -> ClSF m cl 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 -> ClSF m cl a b) -> IO StdGen -> IO (ClSF m cl a b)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> IO StdGen
forall (m :: Type -> Type). MonadIO m => m StdGen
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' :: forall (m :: Type -> Type) cl a b.
MonadIO m =>
ClSF (RandT StdGen m) cl a b -> ClSF m cl a b
evalRandIOS' = ReaderT (TimeInfo cl) m (Automaton (ReaderT (TimeInfo cl) m) a b)
-> Automaton (ReaderT (TimeInfo cl) m) a b
forall (m :: Type -> Type) a b.
Monad m =>
m (Automaton m a b) -> Automaton m a b
performOnFirstSample (ReaderT (TimeInfo cl) m (Automaton (ReaderT (TimeInfo cl) m) a b)
 -> Automaton (ReaderT (TimeInfo cl) m) a b)
-> (ClSF (RandT StdGen m) cl a b
    -> ReaderT
         (TimeInfo cl) m (Automaton (ReaderT (TimeInfo cl) m) a b))
-> ClSF (RandT StdGen m) cl a b
-> Automaton (ReaderT (TimeInfo cl) m) a b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO (Automaton (ReaderT (TimeInfo cl) m) a b)
-> ReaderT
     (TimeInfo cl) m (Automaton (ReaderT (TimeInfo cl) m) a b)
forall a. IO a -> ReaderT (TimeInfo cl) m a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO (Automaton (ReaderT (TimeInfo cl) m) a b)
 -> ReaderT
      (TimeInfo cl) m (Automaton (ReaderT (TimeInfo cl) m) a b))
-> (ClSF (RandT StdGen m) cl a b
    -> IO (Automaton (ReaderT (TimeInfo cl) m) a b))
-> ClSF (RandT StdGen m) cl a b
-> ReaderT
     (TimeInfo cl) m (Automaton (ReaderT (TimeInfo cl) m) a b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ClSF (RandT StdGen m) cl a b
-> IO (Automaton (ReaderT (TimeInfo cl) m) a b)
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 = m a -> ClSF m cl arbitrary a
forall (m :: Type -> Type) b cl a. Monad m => m b -> ClSF m cl a b
constMCl m a
forall a. Random a => m a
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 = ((a, a) -> m a) -> ClSF m cl (a, a) a
forall (m :: Type -> Type) a b cl.
Monad m =>
(a -> m b) -> ClSF m cl a b
arrMCl (a, a) -> m a
forall a. Random a => (a, a) -> m a
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 = m a -> ClSF m cl arbitrary a
forall (m :: Type -> Type) b cl a. Monad m => m b -> ClSF m cl a b
constMCl (m a -> ClSF m cl arbitrary a) -> m a -> ClSF m cl arbitrary a
forall a b. (a -> b) -> a -> b
$ (a, a) -> m a
forall a. Random a => (a, a) -> m a
forall (m :: Type -> Type) a.
(MonadRandom m, Random a) =>
(a, a) -> m a
getRandomR (a, a)
range