{-# LANGUAGE UndecidableInstances #-}
-- Search for UndecidableInstances to see why this is needed
-----------------------------------------------------------------------------
-- |
-- Module : Control.Monad.Writer.Class
-- Copyright : (c) Andy Gill 2001,
-- (c) Oregon Graduate Institute of Science and Technology, 2001
-- License : BSD-style (see the file LICENSE)
--
-- Maintainer : libraries@haskell.org
-- Stability : experimental
-- Portability : non-portable (multi-param classes, functional dependencies)
--
-- The MonadWriter class.
--
-- Inspired by the paper
-- /Functional Programming with Overloading and Higher-Order Polymorphism/,
-- Mark P Jones (<http://web.cecs.pdx.edu/~mpj/pubs/springschool.html>)
-- Advanced School of Functional Programming, 1995.
-----------------------------------------------------------------------------
module Control.Monad.Writer.Class (
MonadWriter(..),
listens,
censor,
) where
import Control.Monad.Trans.Error as Error
import Control.Monad.Trans.Identity as Identity
import Control.Monad.Trans.Maybe as Maybe
import Control.Monad.Trans.Reader
import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS (
RWST, writer, tell, listen, pass)
import qualified Control.Monad.Trans.RWS.Strict as StrictRWS (
RWST, writer, tell, listen, pass)
import Control.Monad.Trans.State.Lazy as Lazy
import Control.Monad.Trans.State.Strict as Strict
import qualified Control.Monad.Trans.Writer.Lazy as Lazy (
WriterT, writer, tell, listen, pass)
import qualified Control.Monad.Trans.Writer.Strict as Strict (
WriterT, writer, tell, listen, pass)
import Control.Monad.Trans.Class (lift)
import Control.Monad
import Data.Monoid
-- ---------------------------------------------------------------------------
-- MonadWriter class
--
-- tell is like tell on the MUD's it shouts to monad
-- what you want to be heard. The monad carries this 'packet'
-- upwards, merging it if needed (hence the Monoid requirement).
--
-- listen listens to a monad acting, and returns what the monad "said".
--
-- pass lets you provide a writer transformer which changes internals of
-- the written object.
class (Monoid w, Monad m) => MonadWriter w m | m -> w where
-- | @'writer' (a,w)@ embeds a simple writer action.
writer :: (a,w) -> m a
writer ~(a, w) = do
tell w
return a
-- | @'tell' w@ is an action that produces the output @w@.
tell :: w -> m ()
tell w = writer ((),w)
-- | @'listen' m@ is an action that executes the action @m@ and adds
-- its output to the value of the computation.
listen :: m a -> m (a, w)
-- | @'pass' m@ is an action that executes the action @m@, which
-- returns a value and a function, and returns the value, applying
-- the function to the output.
pass :: m (a, w -> w) -> m a
-- | @'listens' f m@ is an action that executes the action @m@ and adds
-- the result of applying @f@ to the output to the value of the computation.
--
-- * @'listens' f m = 'liftM' (id *** f) ('listen' m)@
listens :: MonadWriter w m => (w -> b) -> m a -> m (a, b)
listens f m = do
~(a, w) <- listen m
return (a, f w)
-- | @'censor' f m@ is an action that executes the action @m@ and
-- applies the function @f@ to its output, leaving the return value
-- unchanged.
--
-- * @'censor' f m = 'pass' ('liftM' (\\x -> (x,f)) m)@
censor :: MonadWriter w m => (w -> w) -> m a -> m a
censor f m = pass $ do
a <- m
return (a, f)
instance (Monoid w, Monad m) => MonadWriter w (Lazy.WriterT w m) where
writer = Lazy.writer
tell = Lazy.tell
listen = Lazy.listen
pass = Lazy.pass
instance (Monoid w, Monad m) => MonadWriter w (Strict.WriterT w m) where
writer = Strict.writer
tell = Strict.tell
listen = Strict.listen
pass = Strict.pass
instance (Monoid w, Monad m) => MonadWriter w (LazyRWS.RWST r w s m) where
writer = LazyRWS.writer
tell = LazyRWS.tell
listen = LazyRWS.listen
pass = LazyRWS.pass
instance (Monoid w, Monad m) => MonadWriter w (StrictRWS.RWST r w s m) where
writer = StrictRWS.writer
tell = StrictRWS.tell
listen = StrictRWS.listen
pass = StrictRWS.pass
-- ---------------------------------------------------------------------------
-- Instances for other mtl transformers
--
-- All of these instances need UndecidableInstances,
-- because they do not satisfy the coverage condition.
instance (Error e, MonadWriter w m) => MonadWriter w (ErrorT e m) where
writer = lift . writer
tell = lift . tell
listen = Error.liftListen listen
pass = Error.liftPass pass
instance MonadWriter w m => MonadWriter w (IdentityT m) where
writer = lift . writer
tell = lift . tell
listen = Identity.mapIdentityT listen
pass = Identity.mapIdentityT pass
instance MonadWriter w m => MonadWriter w (MaybeT m) where
writer = lift . writer
tell = lift . tell
listen = Maybe.liftListen listen
pass = Maybe.liftPass pass
instance MonadWriter w m => MonadWriter w (ReaderT r m) where
writer = lift . writer
tell = lift . tell
listen = mapReaderT listen
pass = mapReaderT pass
instance MonadWriter w m => MonadWriter w (Lazy.StateT s m) where
writer = lift . writer
tell = lift . tell
listen = Lazy.liftListen listen
pass = Lazy.liftPass pass
instance MonadWriter w m => MonadWriter w (Strict.StateT s m) where
writer = lift . writer
tell = lift . tell
listen = Strict.liftListen listen
pass = Strict.liftPass pass