{-# LANGUAGE CPP #-}
module Control.Effect.Type.ReaderPrim
(
ReaderPrim(..)
, threadReaderPrim
, threadReaderPrimViaClass
, threadReaderPrimViaRegional
) where
import Control.Monad.Trans
import Control.Monad.Reader.Class (MonadReader)
import qualified Control.Monad.Reader.Class as RC
import Control.Monad.Trans.Except (ExceptT(..))
import Control.Monad.Trans.Reader (ReaderT(..))
import qualified Control.Monad.Trans.Reader as R
import qualified Control.Monad.Trans.State.Strict as SSt
import qualified Control.Monad.Trans.State.Lazy as LSt
import qualified Control.Monad.Trans.Writer.Lazy as LWr
import qualified Control.Monad.Trans.Writer.Strict as SWr
import qualified Control.Monad.Trans.Writer.CPS as CPSWr
import Control.Monad.Trans.Cont (ContT(..))
import qualified Control.Monad.Trans.Cont as C
import Control.Effect.Internal.ViaAlg
import Control.Effect.Type.Regional
import Control.Effect.Internal.Reflection
import Control.Effect.Internal.Union
data ReaderPrim i m a where
ReaderPrimAsk :: ReaderPrim i m i
ReaderPrimLocal :: (i -> i) -> m a -> ReaderPrim i m a
instance ( Reifies s (ReifiedEffAlgebra (ReaderPrim i) m)
, Monad m
) => MonadReader i (ViaAlg s (ReaderPrim i) m) where
ask = case reflect @s of
ReifiedEffAlgebra alg -> coerceAlg alg ReaderPrimAsk
{-# INLINE ask #-}
local f m = case reflect @s of
ReifiedEffAlgebra alg -> coerceAlg alg (ReaderPrimLocal f m)
{-# INLINE local #-}
threadReaderPrim :: forall i t m a
. (MonadTrans t, Monad m)
=> ( (forall x. ReaderPrim i m x -> m x)
-> (i -> i) -> t m a -> t m a
)
-> (forall x. ReaderPrim i m x -> m x)
-> ReaderPrim i (t m) a -> t m a
threadReaderPrim h alg = \case
ReaderPrimAsk -> lift (alg ReaderPrimAsk)
ReaderPrimLocal f m -> h alg f m
{-# INLINE threadReaderPrim #-}
threadReaderPrimViaClass :: forall i t m a
. Monad m
=> ( RepresentationalT t
, MonadTrans t
, forall b. MonadReader i b => MonadReader i (t b)
)
=> (forall x. ReaderPrim i m x -> m x)
-> ReaderPrim i (t m) a -> t m a
threadReaderPrimViaClass alg e = reify (ReifiedEffAlgebra alg) $ \(_ :: pr s) ->
case e of
ReaderPrimAsk -> lift (alg ReaderPrimAsk)
ReaderPrimLocal f m -> unViaAlgT (RC.local f (viaAlgT @s @(ReaderPrim i) m))
{-# INLINE threadReaderPrimViaClass #-}
threadReaderPrimViaRegional :: forall i t m a
. ( Monad m
, MonadTrans t
, ThreadsEff t (Regional ())
)
=> (forall x. ReaderPrim i m x -> m x)
-> ReaderPrim i (t m) a -> t m a
threadReaderPrimViaRegional alg ReaderPrimAsk = lift (alg ReaderPrimAsk)
threadReaderPrimViaRegional alg (ReaderPrimLocal f m) =
threadEff (\(Regionally _ m') -> alg $ ReaderPrimLocal f m') (Regionally () m)
{-# INLINE threadReaderPrimViaRegional #-}
#define THREAD_READER(monadT) \
instance ThreadsEff (monadT) (ReaderPrim threadedInput) where \
threadEff = threadReaderPrimViaClass; \
{-# INLINE threadEff #-}
#define THREAD_READER_CTX(ctx, monadT) \
instance ctx => ThreadsEff (monadT) (ReaderPrim threadedInput) where \
threadEff = threadReaderPrimViaClass; \
{-# INLINE threadEff #-}
instance ThreadsEff (ReaderT i') (ReaderPrim i) where
threadEff = threadReaderPrim $ \alg f m ->
R.mapReaderT (alg . ReaderPrimLocal f) m
{-# INLINE threadEff #-}
instance Monoid w => ThreadsEff (CPSWr.WriterT w) (ReaderPrim i) where
threadEff = threadReaderPrim $ \alg f m ->
CPSWr.mapWriterT (alg . ReaderPrimLocal f) m
{-# INLINE threadEff #-}
THREAD_READER(ExceptT e)
THREAD_READER(SSt.StateT s)
THREAD_READER(LSt.StateT s)
THREAD_READER_CTX(Monoid w, LWr.WriterT w)
THREAD_READER_CTX(Monoid w, SWr.WriterT w)
THREAD_READER(C.ContT r)