-- |
-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
-- License    : BSD3
-- Maintainer : ivan.perez@keera.co.uk
--
-- 'MSF's with a 'Reader' monadic layer.
--
-- This module contains functions to work with 'MSF's that include a 'Reader'
-- monadic layer. This includes functions to create new 'MSF's that include an
-- additional layer, and functions to flatten that layer out of the 'MSF`'s
-- transformer stack.
module Control.Monad.Trans.MSF.Reader
    ( module Control.Monad.Trans.Reader
    -- * 'Reader' 'MSF' running and wrapping.
    , readerS
    , runReaderS
    , runReaderS_
    )
  where

-- External imports
import Control.Arrow              (arr, (>>>))
import Control.Monad.Trans.Reader hiding (liftCallCC, liftCatch)

-- Internal imports
import Data.MonadicStreamFunction (MSF, morphGS)

-- * Reader 'MSF' running and wrapping

-- | Build an 'MSF' in the 'Reader' monad from one that takes the reader
-- environment as an extra input. This is the opposite of 'runReaderS'.
readerS :: Monad m => MSF m (r, a) b -> MSF (ReaderT r m) a b
readerS :: forall (m :: * -> *) r a b.
Monad m =>
MSF m (r, a) b -> MSF (ReaderT r m) a b
readerS = forall (m2 :: * -> *) a1 (m1 :: * -> *) b1 a2 b2.
Monad m2 =>
(forall c. (a1 -> m1 (b1, c)) -> a2 -> m2 (b2, c))
-> MSF m1 a1 b1 -> MSF m2 a2 b2
morphGS forall a b. (a -> b) -> a -> b
$ \(r, a) -> m (b, c)
f a
a -> forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT forall a b. (a -> b) -> a -> b
$ \r
r -> (r, a) -> m (b, c)
f (r
r, a
a)

-- | Build an 'MSF' that takes an environment as an extra input from one on the
-- 'Reader' monad. This is the opposite of 'readerS'.
runReaderS :: Monad m => MSF (ReaderT r m) a b -> MSF m (r, a) b
runReaderS :: forall (m :: * -> *) r a b.
Monad m =>
MSF (ReaderT r m) a b -> MSF m (r, a) b
runReaderS = forall (m2 :: * -> *) a1 (m1 :: * -> *) b1 a2 b2.
Monad m2 =>
(forall c. (a1 -> m1 (b1, c)) -> a2 -> m2 (b2, c))
-> MSF m1 a1 b1 -> MSF m2 a2 b2
morphGS forall a b. (a -> b) -> a -> b
$ \a -> ReaderT r m (b, c)
f (r
r, a
a) -> forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (a -> ReaderT r m (b, c)
f a
a) r
r

-- | Build an 'MSF' /function/ that takes a fixed environment as additional
-- input, from an MSF in the 'Reader' monad.
runReaderS_ :: Monad m => MSF (ReaderT s m) a b -> s -> MSF m a b
runReaderS_ :: forall (m :: * -> *) s a b.
Monad m =>
MSF (ReaderT s m) a b -> s -> MSF m a b
runReaderS_ MSF (ReaderT s m) a b
msf s
s = forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr (\a
a -> (s
s, a
a)) forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> forall (m :: * -> *) r a b.
Monad m =>
MSF (ReaderT r m) a b -> MSF m (r, a) b
runReaderS MSF (ReaderT s m) a b
msf