ether-0.1.0.0: src/Control/Monad/Trans/Ether/Writer.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- | See "Control.Monad.Trans.Writer".
module Control.Monad.Trans.Ether.Writer
(
-- * The Writer monad
Writer
, writer
, runWriter
, execWriter
-- * The WriterT monad transformer
, WriterT
, writerT
, runWriterT
, execWriterT
, mapWriterT
-- * Writer operations
, tell
, listen
, pass
-- * Lifting other operations
, liftCallCC
, liftCatch
, liftListen
, liftPass
) where
import Data.Proxy (Proxy(Proxy))
import Data.Functor.Identity (Identity(..))
import Data.Coerce (coerce)
import Control.Applicative (Alternative)
import Control.Monad (MonadPlus)
import Control.Monad.Fix (MonadFix)
import Control.Monad.Trans.Class (MonadTrans, lift)
import Control.Monad.IO.Class (MonadIO)
import Control.Ether.Tagged (Taggable(..), Tagged(..))
import qualified Control.Ether.Util as Util
import GHC.Generics (Generic)
import qualified Control.Newtype as NT
import qualified Control.Monad.Signatures as Sig
import qualified Control.Monad.Trans.Writer.Lazy as Trans
import qualified Control.Monad.Cont.Class as Class
import qualified Control.Monad.Reader.Class as Class
import qualified Control.Monad.State.Class as Class
import qualified Control.Monad.Writer.Class as Class
import qualified Control.Monad.Error.Class as Class
-- | The parametrizable writer monad.
--
-- Computations can accumulate a monoid value.
--
-- The 'return' function produces the output 'mempty', while '>>=' combines
-- the outputs of the subcomputations using 'mappend'.
type Writer tag w = WriterT tag w Identity
-- | The writer monad transformer.
--
-- The 'return' function produces the output 'mempty', while '>>=' combines
-- the outputs of the subcomputations using 'mappend'.
newtype WriterT tag w m a = WriterT (Trans.WriterT w m a)
deriving ( Generic
, Functor, Applicative, Alternative, Monad, MonadPlus
, MonadFix, MonadTrans, MonadIO )
instance NT.Newtype (WriterT tag w m a)
instance Taggable (WriterT tag w m) where
type Tag (WriterT tag w m) = 'Just tag
type Inner (WriterT tag w m) = 'Just m
instance Tagged (WriterT tag w m) tag where
type Untagged (WriterT tag w m) = Trans.WriterT w m
-- | Constructor for computations in the writer monad transformer.
writerT :: proxy tag -> m (a, w) -> WriterT tag w m a
writerT t = tagged t . Trans.WriterT
-- | Constructor for computations in the writer monad
-- (the inverse of 'runWriter').
writer :: Monad m => proxy tag -> (a, w) -> WriterT tag w m a
writer t = tagged t . Trans.writer
-- | Runs a 'WriterT' and returns both the normal value
-- and the final accumulator.
runWriterT :: proxy tag -> WriterT tag w m a -> m (a, w)
runWriterT t = Trans.runWriterT . untagged t
-- | Runs a 'Writer' and returns both the normal value
-- and the final accumulator.
runWriter :: proxy tag -> Writer tag w a -> (a, w)
runWriter t = Trans.runWriter . untagged t
-- | Runs a 'WriterT' and returns the final accumulator,
-- discarding the normal value.
execWriterT :: Monad m => proxy tag -> WriterT tag w m a -> m w
execWriterT t = Trans.execWriterT . untagged t
-- | Runs a 'Writer' and returns the final accumulator,
-- discarding the normal value.
execWriter :: proxy tag -> Writer tag w a -> w
execWriter t = Trans.execWriter . untagged t
-- | Transform the computation inside a 'WriterT'.
--
-- * @'runWriterT' tag ('mapWriterT' tag f m) = f ('runWriterT' tag m)@
mapWriterT :: proxy tag -> (m (a, w) -> n (b, w')) -> WriterT tag w m a -> WriterT tag w' n b
mapWriterT t f m = tagged t $ Trans.mapWriterT f (coerce m)
-- | Appends a value to the accumulator within the monad.
tell :: Monad m => proxy tag -> w -> WriterT tag w m ()
tell t w = writer t ((), w)
-- | Executes an action and adds its accumulator to the value of the computation.
listen :: (Monoid w, Monad m) => proxy tag -> WriterT tag w m a -> WriterT tag w m (a, w)
listen t m = tagged t $ Trans.listen (coerce m)
-- | Executes an action which returns a value and a function, and returns the
-- value, applying the function to the accumulator.
pass :: (Monoid w, Monad m) => proxy tag -> WriterT tag w m (a, w -> w) -> WriterT tag w m a
pass t m = tagged t $ Trans.pass (coerce m)
-- | Lift a @catchE@ operation to the new monad.
liftCatch :: proxy tag -> Sig.Catch e m (a, w) -> Sig.Catch e (WriterT tag w m) a
liftCatch t f m h = tagged t $ Trans.liftCatch f (coerce m) (coerce h)
-- | Lift a @callCC@ operation to the new monad.
liftCallCC :: Monoid w => proxy tag -> Sig.CallCC m (a, w) (b, w) -> Sig.CallCC (WriterT tag w m) a b
liftCallCC t callCC f = tagged t $ Trans.liftCallCC callCC (coerce f)
-- | Lift a @listen@ operation to the new monad.
liftListen :: Monad m => proxy tag -> Sig.Listen w' m (a, w) -> Sig.Listen w' (WriterT tag w m) a
liftListen t f m = tagged t $ Util.liftListen_WriterT f (coerce m)
-- | Lift a @pass@ operation to the new monad.
liftPass :: Monad m => proxy tag -> Sig.Pass w' m (a, w) -> Sig.Pass w' (WriterT tag w m) a
liftPass t f m = tagged t $ Util.liftPass_WriterT f (coerce m)
instance (Monoid w, Class.MonadCont m) => Class.MonadCont (WriterT tag w m) where
callCC = liftCallCC Proxy Class.callCC
instance (Monoid w, Class.MonadReader r m) => Class.MonadReader r (WriterT tag w m) where
ask = lift Class.ask
local = mapWriterT Proxy . Class.local
reader = lift . Class.reader
instance (Monoid w, Class.MonadState s m) => Class.MonadState s (WriterT tag w m) where
get = lift Class.get
put = lift . Class.put
state = lift . Class.state
instance (Monoid w, Class.MonadWriter w' m) => Class.MonadWriter w' (WriterT tag w m) where
writer = lift . Class.writer
tell = lift . Class.tell
listen = liftListen Proxy Class.listen
pass = liftPass Proxy Class.pass
instance (Monoid w, Class.MonadError e m) => Class.MonadError e (WriterT tag w m) where
throwError = lift . Class.throwError
catchError = liftCatch Proxy Class.catchError