{-# LANGUAGE Rank2Types #-} -- | '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_ -- ** Alternative implementation using internal type. , readerS' , runReaderS' -- ** Alternative implementation using generic lifting. , runReaderS'' ) where -- External import Control.Monad.Trans.Reader hiding (liftCallCC, liftCatch) -- Avoid conflicting exports -- Internal import Control.Monad.Trans.MSF.GenLift import Data.MonadicStreamFunction -- * 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 (s, a) b -> MSF (ReaderT s m) a b readerS msf = MSF $ \a -> do (b, msf') <- ReaderT $ \s -> unMSF msf (s, a) return (b, readerS msf') -- | 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 s m) a b -> MSF m (s, a) b runReaderS msf = MSF $ \(s,a) -> do (b, msf') <- runReaderT (unMSF msf a) s return (b, runReaderS msf') -- | Build an 'MSF' /function/ that takes a fixed environment as additional -- input, from an 'MSF' in the 'Reader' monad. -- -- This should be always equal to: -- -- @ -- runReaderS_ msf s = arr (\a -> (s,a)) >>> runReaderS msf -- @ -- -- although possibly more efficient. runReaderS_ :: Monad m => MSF (ReaderT s m) a b -> s -> MSF m a b runReaderS_ msf s = MSF $ \a -> do (b, msf') <- runReaderT (unMSF msf a) s return (b, runReaderS_ msf' s) -- ** Alternative implementation using internal type. -- TODO: One one should exist, ideally. -- | Alternative version of 'readerS'. readerS' :: Monad m => MSF m (s, a) b -> MSF (ReaderT s m) a b readerS' = lifterS wrapReaderT -- | Alternative version of 'runReaderS' wrapping/unwrapping functions. runReaderS' :: Monad m => MSF (ReaderT s m) a b -> MSF m (s, a) b runReaderS' = lifterS unwrapReaderT wrapReaderT :: ((s, a) -> m b) -> a -> ReaderT s m b wrapReaderT g i = ReaderT $ g . flip (,) i unwrapReaderT :: (a -> ReaderT s m b) -> (s, a) -> m b unwrapReaderT g i = uncurry (flip runReaderT) $ second g i -- ** Alternative implementation using generic lifting. -- | Alternative version of 'runReaderS'. runReaderS'' :: Monad m => MSF (ReaderT s m) a b -> MSF m (s, a) b runReaderS'' = transG transformInput transformOutput where transformInput (_, a) = return a transformOutput (s, _) m1 = do (r, c) <- runReaderT m1 s return (r, Just c) {- readerS'' :: Monad m => MSF m (s, a) b -> MSF (ReaderT s m) a b readerS'' = transS transformInput transformOutput where transformInput :: a -> m (s, a) transformInput a = (,) <$> asks <*> pure a transformOutput _ = lift -} -- Another alternative: -- -- type ReaderWrapper s m = Wrapper (ReaderT s m) m ((,) s) Id -- type ReaderUnwrapper s m = Unwrapper (ReaderT s m) m ((,) s) Id -- -- and use the types: -- -- wrapReaderT :: ReaderWrapper s m -- unwrapReaderT :: ReaderUnwrapper s m