-- | This module defines operations related to monads in ReWire, including 
-- functions for defining looping monadic actions, and simplifying a tower
-- of monad transformers down to the simple ReacT action required by rwc.
-- It provides type synonyms for distinguishing looping devices and stateful devices
-- that run indefinitely.
module ReWire.Monad 
      ( iter, iterSt
      , extrudeDev, extrudeStateDev
      , Dev, StateDev
      ) where

import ReWire

iter :: (i -> o) -> i -> ReacT i o Identity ()
iter :: forall i o. (i -> o) -> i -> ReacT i o Identity ()
iter i -> o
f i
i = o -> ReacT i o Identity i
forall (m :: * -> *) o i. Monad m => o -> ReacT i o m i
signal (i -> o
f i
i) ReacT i o Identity i
-> (i -> ReacT i o Identity ()) -> ReacT i o Identity ()
forall a b.
ReacT i o Identity a
-> (a -> ReacT i o Identity b) -> ReacT i o Identity b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (i -> o) -> i -> ReacT i o Identity ()
forall i o. (i -> o) -> i -> ReacT i o Identity ()
iter i -> o
f

iterSt :: (i -> s -> (o, s)) -> i -> ReacT i o (StateT s Identity) ()
iterSt :: forall i s o.
(i -> s -> (o, s)) -> i -> ReacT i o (StateT s Identity) ()
iterSt i -> s -> (o, s)
f i
i = do
      (o, s) <- StateT s Identity (o, s) -> ReacT i o (StateT s Identity) (o, s)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (StateT s Identity (o, s) -> ReacT i o (StateT s Identity) (o, s))
-> StateT s Identity (o, s) -> ReacT i o (StateT s Identity) (o, s)
forall a b. (a -> b) -> a -> b
$ StateT s Identity s
forall (m :: * -> *) s. Monad m => StateT s m s
get StateT s Identity s
-> (s -> StateT s Identity (o, s)) -> StateT s Identity (o, s)
forall a b.
StateT s Identity a
-> (a -> StateT s Identity b) -> StateT s Identity b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (o, s) -> StateT s Identity (o, s)
forall a. a -> StateT s Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return ((o, s) -> StateT s Identity (o, s))
-> (s -> (o, s)) -> s -> StateT s Identity (o, s)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. i -> s -> (o, s)
f i
i
      lift $ put s
      signal o >>= iterSt f

-- | Should be used to represent a looping device that operates indefinitely.
-- Formally, distinguishes a Re_+ device from an Re_INF device for embedding.
type Dev i o = ReacT i o Identity ()

-- | Similar to `Dev`, but for stateful computations.
type StateDev i o m = ReacT i o m ()

-- | Extrude a stateful device to reduce the monad transformer tower.
{-# INLINE extrudeStateDev #-}
extrudeStateDev :: Monad m => StateDev i o (StateT s m) -> s -> StateDev i o m
extrudeStateDev :: forall (m :: * -> *) i o s.
Monad m =>
StateDev i o (StateT s m) -> s -> StateDev i o m
extrudeStateDev = ReacT i o (StateT s m) () -> s -> ReacT i o m ()
forall (m :: * -> *) i o s a.
Monad m =>
ReacT i o (StateT s m) a -> s -> ReacT i o m a
extrude

-- | Extrude a stateful device to remove the final StateT monad transformer.
{-# INLINE extrudeDev #-}
extrudeDev :: StateDev i o (StateT s Identity) -> s -> Dev i o
extrudeDev :: forall i o s. StateDev i o (StateT s Identity) -> s -> Dev i o
extrudeDev = ReacT i o (StateT s Identity) () -> s -> ReacT i o Identity ()
forall (m :: * -> *) i o s a.
Monad m =>
ReacT i o (StateT s m) a -> s -> ReacT i o m a
extrude