monad-classes-0.3.2.2: Control/Monad/Classes/Writer.hs
module Control.Monad.Classes.Writer where
import Control.Applicative
import Control.Monad
import qualified Control.Monad.Trans.Writer.Lazy as WL
import qualified Control.Monad.Trans.Writer.Strict as WS
import qualified Control.Monad.Trans.State.Lazy as SL
import qualified Control.Monad.Trans.State.Strict as SS
import Control.Monad.Base
import Control.Monad.Trans.Control
import Control.Monad.Trans.Class
import Control.Monad.IO.Class
import Control.Monad.Classes.Core
import Control.Monad.Classes.Effects
import Control.Monad.Classes.Proxied
import Data.Monoid ((<>))
import Data.Peano
type instance CanDo (WL.WriterT w m) eff = WriterCanDo w eff
type instance CanDo (WS.WriterT w m) eff = WriterCanDo w eff
type instance CanDo (CustomWriterT' w n m) eff = WriterCanDo w eff
type family WriterCanDo w eff where
WriterCanDo w (EffWriter w) = True
WriterCanDo w eff = False
class Monad m => MonadWriterN (n :: Peano) w m where
tellN :: Proxy# n -> (w -> m ())
instance (Monad m, Monoid w) => MonadWriterN Zero w (WL.WriterT w m) where
tellN _ = WL.tell
instance (Monad m, Monoid w) => MonadWriterN Zero w (WS.WriterT w m) where
tellN _ = WS.tell
instance (Monad m, Monoid w) => MonadWriterN Zero w (SL.StateT w m) where
-- lazy
tellN _ w = SL.modify (<> w)
instance (Monad m, Monoid w) => MonadWriterN Zero w (SS.StateT w m) where
tellN _ w = modify' (<> w)
where
modify' :: (s -> s) -> SS.StateT s m ()
modify' f = SS.state (\s -> let s' = f s in s' `seq` ((), s'))
instance Monad m => MonadWriterN Zero w (CustomWriterT' w m m) where
tellN _ w = CustomWriterT $ Proxied $ \px -> reflect px w
instance (MonadTrans t, Monad (t m), MonadWriterN n w m, Monad m)
=> MonadWriterN (Succ n) w (t m)
where
tellN _ = lift . tellN (proxy# :: Proxy# n)
-- | The @'MonadWriter' w m@ constraint asserts that @m@ is a monad stack
-- that supports outputting values of type @w@
type MonadWriter w m = MonadWriterN (Find (EffWriter w) m) w m
-- | @'tell' w@ is an action that produces the output @w@
tell :: forall w m . MonadWriter w m => w -> m ()
tell = tellN (proxy# :: Proxy# (Find (EffWriter w) m))
runWriterStrict :: (Monad m, Monoid w) => SS.StateT w m a -> m (a, w)
runWriterStrict = flip SS.runStateT mempty
evalWriterStrict :: (Monad m, Monoid w) => SS.StateT w m a -> m a
evalWriterStrict = flip SS.evalStateT mempty
execWriterStrict :: (Monad m, Monoid w) => SS.StateT w m a -> m w
execWriterStrict = flip SS.execStateT mempty
runWriterLazy :: (Monad m, Monoid w) => WL.WriterT w m a -> m (a, w)
runWriterLazy = WL.runWriterT
evalWriterLazy :: (Monad m, Monoid w) => WL.WriterT w m a -> m a
evalWriterLazy = liftM fst . runWriterLazy
execWriterLazy :: (Monad m, Monoid w) => WL.WriterT w m a -> m w
execWriterLazy = WL.execWriterT
-- The separation between 'n' and 'm' types is needed to implement
-- the MonadTransControl instance
newtype CustomWriterT' w n m a = CustomWriterT (Proxied (w -> n ()) m a)
deriving (Functor, Applicative, Monad, Alternative, MonadPlus, MonadBase b, MonadIO)
type CustomWriterT w m = CustomWriterT' w m m
instance MonadTrans (CustomWriterT' w n) where
lift a = CustomWriterT $ Proxied $ \_ -> a
instance MonadTransControl (CustomWriterT' w n) where
type StT (CustomWriterT' w n) a = StT (Proxied (w -> n ())) a
liftWith = defaultLiftWith CustomWriterT (\(CustomWriterT a) -> a)
restoreT = defaultRestoreT CustomWriterT
instance MonadBaseControl b m => MonadBaseControl b (CustomWriterT' w n m) where
type StM (CustomWriterT' w n m) a = ComposeSt (CustomWriterT' w n) m a
liftBaseWith = defaultLiftBaseWith
restoreM = defaultRestoreM
evalWriterWith
:: forall w m a . (w -> m ())
-> CustomWriterT w m a
-> m a
evalWriterWith tellFn a =
reify tellFn $ \px ->
case a of
CustomWriterT (Proxied a') -> a' px
-- | Transform all writer requests with a given function
mapWriter
:: forall w1 w2 m a . MonadWriter w2 m
=> (w1 -> w2)
-> CustomWriterT w1 m a
-> m a
mapWriter f a =
evalWriterWith (\w1 -> tell (f w1)) a