{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, TypeOperators, UndecidableInstances #-}
module Control.Carrier.Writer.Strict
(
runWriter
, execWriter
, WriterC(..)
, module Control.Effect.Writer
) where
import Control.Algebra
import Control.Applicative (Alternative(..))
import Control.Carrier.State.Strict
import Control.Effect.Writer
import Control.Monad (MonadPlus(..))
import qualified Control.Monad.Fail as Fail
import Control.Monad.Fix
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
runWriter :: Monoid w => WriterC w m a -> m (w, a)
runWriter (WriterC m) = runState mempty m
{-# INLINE runWriter #-}
execWriter :: (Monoid w, Functor m) => WriterC w m a -> m w
execWriter = fmap fst . runWriter
{-# INLINE execWriter #-}
newtype WriterC w m a = WriterC (StateC w m a)
deriving (Alternative, Applicative, Functor, Monad, Fail.MonadFail, MonadFix, MonadIO, MonadPlus, MonadTrans)
instance (Monoid w, Algebra sig m, Effect sig) => Algebra (Writer w :+: sig) (WriterC w m) where
alg (L (Tell w k)) = WriterC (modify (`mappend` w)) >> k
alg (L (Listen m k)) = WriterC (StateC (\ w -> do
(w', a) <- runWriter m
let w'' = mappend w w'
w'' `seq` pure (w'', (w', a))))
>>= uncurry k
alg (L (Censor f m k)) = WriterC (StateC (\ w -> do
(w', a) <- runWriter m
let w'' = mappend w (f w')
w'' `seq` pure (w'', a)))
>>= k
alg (R other) = WriterC (alg (R (handleCoercible other)))
{-# INLINE alg #-}