{-# LANGUAGE CPP #-}
module Control.Effect.Type.WriterPrim
(
WriterPrim(..)
, threadWriterPrim
, threadWriterPrimViaClass
, algListenPrimIntoWriterPrim
) where
import Control.Monad.Trans
import Control.Monad.Trans.Reader (ReaderT)
import Control.Monad.Trans.Except (ExceptT)
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.Writer.Class
import Control.Effect.Internal.ViaAlg
import Control.Effect.Internal.Reflection
import Control.Effect.Internal.Union
import Control.Effect.Type.ListenPrim
data WriterPrim w m a where
WriterPrimTell :: w -> WriterPrim w m ()
WriterPrimListen :: m a -> WriterPrim w m (w, a)
WriterPrimPass :: m (w -> w, a) -> WriterPrim w m a
threadWriterPrim :: forall w t m a
. ( MonadTrans t
, ThreadsEff t (ListenPrim w)
, Monad m
)
=> ( (forall x. WriterPrim w m x -> m x)
-> t m (w -> w, a) -> t m a
)
-> (forall x. WriterPrim w m x -> m x)
-> WriterPrim w (t m) a -> t m a
threadWriterPrim h alg = \case
WriterPrimTell w -> lift (alg (WriterPrimTell w))
WriterPrimListen m -> (`threadEff` (ListenPrimListen m)) $ \case
ListenPrimTell w -> alg (WriterPrimTell w)
ListenPrimListen m' -> alg (WriterPrimListen m')
WriterPrimPass m -> h alg m
{-# INLINE threadWriterPrim #-}
instance ( Reifies s (ReifiedEffAlgebra (WriterPrim w) m)
, Monoid w
, Monad m
)
=> MonadWriter w (ViaAlg s (WriterPrim w) m) where
tell w = case reflect @s of
ReifiedEffAlgebra alg -> coerceAlg alg (WriterPrimTell w)
{-# INLINE tell #-}
listen m = case reflect @s of
ReifiedEffAlgebra alg ->
fmap (\(s, a) -> (a, s)) $ coerceAlg alg (WriterPrimListen m)
{-# INLINE listen #-}
pass m = case reflect @s of
ReifiedEffAlgebra alg ->
coerceAlg alg (WriterPrimPass (fmap (\(a,f) -> (f, a)) m))
{-# INLINE pass #-}
threadWriterPrimViaClass :: forall w t m a
. (Monoid w, MonadTrans t, Monad m)
=> ( RepresentationalT t
, forall b. MonadWriter w b => MonadWriter w (t b)
)
=> (forall x. WriterPrim w m x -> m x)
-> WriterPrim w (t m) a -> t m a
threadWriterPrimViaClass alg = \case
WriterPrimTell w -> lift (alg (WriterPrimTell w))
WriterPrimListen m ->
reify (ReifiedEffAlgebra alg) $ \(_ :: pr s) ->
unViaAlgT
$ fmap (\(f, a) -> (a, f))
$ listen
$ viaAlgT @s @(WriterPrim w) m
WriterPrimPass m ->
reify (ReifiedEffAlgebra alg) $ \(_ :: pr s) ->
unViaAlgT
$ pass
$ fmap (\(f, a) -> (a, f))
$ viaAlgT @s @(WriterPrim w) m
{-# INLINE threadWriterPrimViaClass #-}
#define THREAD_WRITERPRIM(monadT) \
instance Monoid threadedMonoid \
=> ThreadsEff (monadT) (WriterPrim threadedMonoid) where \
threadEff = threadWriterPrimViaClass; \
{-# INLINE threadEff #-}
THREAD_WRITERPRIM(ReaderT i)
THREAD_WRITERPRIM(ExceptT e)
THREAD_WRITERPRIM(LSt.StateT s)
THREAD_WRITERPRIM(SSt.StateT s)
instance Monoid s => ThreadsEff (LWr.WriterT s) (WriterPrim w) where
threadEff = threadWriterPrim $ \alg m ->
LWr.WriterT
$ alg
$ WriterPrimPass
$ fmap (\((f,a), s) -> (f, (a, s)))
$ LWr.runWriterT m
{-# INLINE threadEff #-}
instance Monoid s => ThreadsEff (SWr.WriterT s) (WriterPrim w) where
threadEff = threadWriterPrim $ \alg m ->
SWr.WriterT
$ alg
$ WriterPrimPass
$ fmap (\((f,a), s) -> (f, (a, s)))
$ SWr.runWriterT m
{-# INLINE threadEff #-}
instance Monoid s => ThreadsEff (CPSWr.WriterT s) (WriterPrim w) where
threadEff = threadWriterPrim $ \alg m ->
CPSWr.writerT
$ alg
$ WriterPrimPass
$ fmap (\((f,a), s) -> (f, (a, s)))
$ CPSWr.runWriterT m
{-# INLINE threadEff #-}
algListenPrimIntoWriterPrim :: Algebra' (ListenPrim w ': p) m a
-> (m (w -> w, a) -> m a)
-> Algebra' (WriterPrim w ': p) m a
algListenPrimIntoWriterPrim alg h = powerAlg (weakenAlg alg) $ \case
WriterPrimTell w -> (alg . inj) (ListenPrimTell w)
WriterPrimListen m -> (alg . inj) (ListenPrimListen m)
WriterPrimPass m -> h m
{-# INLINE algListenPrimIntoWriterPrim #-}