{-# LANGUAGE DerivingVia #-}
{-# OPTIONS_HADDOCK not-home #-}
module Control.Effect.Internal.Writer where
import Data.Coerce
import Data.Tuple (swap)
import Control.Applicative
import Control.Monad
import Control.Effect
import Control.Effect.Bracket
import Control.Effect.Type.ListenPrim
import Control.Effect.Type.WriterPrim
import Control.Effect.Carrier
import Control.Monad.Trans.Control hiding (embed)
import qualified Control.Monad.Catch as C
import Control.Monad.Trans.Writer.CPS (WriterT, writerT, runWriterT)
import qualified Control.Monad.Trans.Writer.CPS as W
import qualified Control.Monad.Trans.Writer.Lazy as LW
import Control.Effect.Internal.Utils
data Tell s m a where
Tell :: s -> Tell s m ()
data Listen s m a where
Listen :: m a -> Listen s m (s, a)
data Pass s m a where
Pass :: m (s -> s, a) -> Pass s m a
newtype TellC s m a = TellC {
unTellC :: WriterT s m a
}
deriving ( Functor, Applicative, Monad
, Alternative, MonadPlus
, MonadFix, MonadFail, MonadIO
)
via WriterT s m
deriving MonadTrans via (WriterT s)
instance MonadThrow m => MonadThrow (TellC s m) where
throwM = lift . C.throwM
{-# INLINEABLE throwM #-}
instance (Monoid s, MonadCatch m) => MonadCatch (TellC s m) where
catch (TellC m) h = TellC $ writerT $
runWriterT m `C.catch` (runWriterT . unTellC #. h)
{-# INLINEABLE catch #-}
instance (Monoid s, MonadMask m) => MonadMask (TellC s m) where
mask main = TellC $ writerT $ C.mask $ \restore ->
runWriterT (unTellC (main (TellC #. W.mapWriterT restore .# unTellC)))
{-# INLINEABLE mask #-}
uninterruptibleMask main = TellC $ writerT $ C.uninterruptibleMask $ \restore ->
runWriterT (unTellC (main (TellC #. W.mapWriterT restore .# unTellC)))
{-# INLINEABLE uninterruptibleMask #-}
generalBracket acquire release use =
coerceAlg
(threadEff @(WriterT s) @_ @m
(\(GeneralBracket a r u) -> C.generalBracket a r u)
)
(GeneralBracket acquire release use)
{-# INLINEABLE generalBracket #-}
instance MonadBase b m => MonadBase b (TellC s m) where
liftBase = lift . liftBase
{-# INLINEABLE liftBase #-}
instance ( MonadBaseControl b m
, Monoid s
)
=> MonadBaseControl b (TellC s m) where
type StM (TellC s m) a = StM m (a, s)
liftBaseWith = defaultLiftBaseWith
{-# INLINEABLE liftBaseWith #-}
restoreM = defaultRestoreM
{-# INLINEABLE restoreM #-}
instance Monoid s => MonadTransControl (TellC s) where
type StT (TellC s) a = (a, s)
liftWith main = lift (main (runWriterT .# unTellC))
{-# INLINEABLE liftWith #-}
restoreT = TellC #. writerT
{-# INLINEABLE restoreT #-}
instance ( Carrier m
, Monoid s
, Threads (WriterT s) (Prims m)
)
=> Carrier (TellC s m) where
type Derivs (TellC s m) = Tell s ': Derivs m
type Prims (TellC s m) = Prims m
algPrims = coerceAlg (thread @(WriterT s) (algPrims @m))
{-# INLINEABLE algPrims #-}
reformulate n alg = powerAlg (reformulate (n . lift) alg) $ \case
Tell s -> n (TellC (W.tell s))
{-# INLINEABLE reformulate #-}
newtype ListenC s m a = ListenC {
unListenC :: WriterT s m a
}
deriving ( Functor, Applicative, Monad
, Alternative, MonadPlus
, MonadFix, MonadFail, MonadIO
, MonadThrow, MonadCatch, MonadMask
, MonadBase b, MonadBaseControl b
)
via TellC s m
deriving (MonadTrans, MonadTransControl) via (TellC s)
instance ( Carrier m
, Monoid s
, Threads (WriterT s) (Prims m)
)
=> Carrier (ListenC s m) where
type Derivs (ListenC s m) = Listen s ': Tell s ': Derivs m
type Prims (ListenC s m) = ListenPrim s ': Prims m
algPrims =
powerAlg (
coerce (algPrims @(TellC s m))
) $ \case
ListenPrimTell s -> ListenC $ W.tell s
ListenPrimListen (ListenC m) -> ListenC $ do
(a, s) <- W.listen m
return (s, a)
{-# INLINEABLE algPrims #-}
reformulate n alg =
powerAlg (
coerceReform (reformulate @(TellC s m)) n (weakenAlg alg)
) $ \case
Listen m -> (alg . inj) $ ListenPrimListen m
{-# INLINEABLE reformulate #-}
newtype WriterC s m a = WriterC {
unWriterC :: WriterT s m a
}
deriving ( Functor, Applicative, Monad
, Alternative, MonadPlus
, MonadFix, MonadFail, MonadIO
, MonadThrow, MonadCatch, MonadMask
, MonadBase b, MonadBaseControl b
)
via TellC s m
deriving (MonadTrans, MonadTransControl) via (TellC s)
instance ( Carrier m
, Monoid s
, Threads (WriterT s) (Prims m)
)
=> Carrier (WriterC s m) where
type Derivs (WriterC s m) = Pass s ': Listen s ': Tell s ': Derivs m
type Prims (WriterC s m) = WriterPrim s ': Prims m
algPrims =
algListenPrimIntoWriterPrim (
coerce (algPrims @(ListenC s m))
) $ \(WriterC m) -> WriterC $ W.pass $ do
(f, a) <- m
return (a, f)
{-# INLINEABLE algPrims #-}
reformulate n alg =
powerAlg (
powerAlg (
coerceReform (reformulate @(TellC s m)) n (weakenAlg alg)
) $ \case
Listen m -> (alg . inj) $ WriterPrimListen m
) $ \case
Pass m -> (alg . inj) $ WriterPrimPass m
{-# INLINEABLE reformulate #-}
newtype TellLazyC s m a = TellLazyC {
unTellLazyC :: LW.WriterT s m a
}
deriving ( Functor, Applicative, Monad
, Alternative, MonadPlus
, MonadThrow, MonadCatch, MonadMask
, MonadFix, MonadFail, MonadIO
, MonadBase b, MonadBaseControl b
)
deriving (MonadTrans, MonadTransControl)
instance ( Monoid s
, Carrier m
, Threads (LW.WriterT s) (Prims m)
)
=> Carrier (TellLazyC s m) where
type Derivs (TellLazyC s m) = Tell s ': Derivs m
type Prims (TellLazyC s m) = Prims m
algPrims = coerce (thread @(LW.WriterT s) (algPrims @m))
{-# INLINEABLE algPrims #-}
reformulate n alg = powerAlg (reformulate (n . lift) alg) $ \case
Tell s -> n $ TellLazyC $ LW.tell s
{-# INLINEABLE reformulate #-}
newtype ListenLazyC s m a = ListenLazyC {
unListenLazyC :: LW.WriterT s m a
}
deriving ( Functor, Applicative, Monad
, Alternative, MonadPlus
, MonadThrow, MonadCatch, MonadMask
, MonadFix, MonadFail, MonadIO
, MonadBase b, MonadBaseControl b
)
deriving (MonadTrans, MonadTransControl)
instance ( Monoid s
, Carrier m
, Threads (LW.WriterT s) (Prims m)
)
=> Carrier (ListenLazyC s m) where
type Derivs (ListenLazyC s m) = Listen s ': Tell s ': Derivs m
type Prims (ListenLazyC s m) = ListenPrim s ': Prims m
algPrims =
powerAlg (
coerce (algPrims @(TellLazyC s m))
) $ \case
ListenPrimTell w ->
ListenLazyC $ LW.tell w
ListenPrimListen (ListenLazyC m) ->
ListenLazyC $ swap <$> LW.listen m
{-# INLINEABLE algPrims #-}
reformulate n alg =
powerAlg (
coerceReform (reformulate @(TellLazyC s m)) n (weakenAlg alg)
) $ \case
Listen m -> (alg . inj) $ ListenPrimListen m
{-# INLINEABLE reformulate #-}
newtype WriterLazyC s m a = WriterLazyC {
_unWriterLazyC :: LW.WriterT s m a
}
deriving ( Functor, Applicative, Monad
, Alternative, MonadPlus
, MonadThrow, MonadCatch, MonadMask
, MonadFix, MonadFail, MonadIO
, MonadBase b, MonadBaseControl b
)
deriving (MonadTrans, MonadTransControl)
instance ( Monoid s
, Carrier m
, Threads (LW.WriterT s) (Prims m)
)
=> Carrier (WriterLazyC s m) where
type Derivs (WriterLazyC s m) = Pass s ': Listen s ': Tell s ': Derivs m
type Prims (WriterLazyC s m) = WriterPrim s ': Prims m
algPrims =
algListenPrimIntoWriterPrim (
coerce (algPrims @(ListenLazyC s m))
) $ \(WriterLazyC m) -> WriterLazyC $ LW.pass (swap <$> m)
{-# INLINEABLE algPrims #-}
reformulate n alg =
powerAlg (
powerAlg (
coerceReform (reformulate @(TellLazyC s m)) n (weakenAlg alg)
) $ \case
Listen m -> (alg . inj) $ WriterPrimListen m
) $ \case
Pass m -> (alg . inj) $ WriterPrimPass m
{-# INLINEABLE reformulate #-}
class ( forall s. Monoid s => Threads (WriterT s) p
) => WriterThreads p
instance ( forall s. Monoid s => Threads (WriterT s) p
) => WriterThreads p
class ( forall s. Monoid s => Threads (LW.WriterT s) p
) => WriterLazyThreads p
instance ( forall s. Monoid s => Threads (LW.WriterT s) p
) => WriterLazyThreads p