module Control.Effect.Writer
  ( Writer(..)
  , tell
  , listen
  , censor
  ) where

import Control.Effect.Base

-- | The @'Writer' w@ effect allows the accumulation of monoidal values of type
-- @w@.
--
-- Instances should obey the following laws:
--
--   * @'tell' /x/ '*>' 'tell' /y/@ ≡ @'tell' (/x/ '<>' /y/)@
--   * @'listen' ('tell' /x/)@ ≡ @(/x/,) '<$>' 'tell' /x/@
--   * @'censor' /f/ ('tell' /x/)@ ≡ @'tell' (/f/ /x/)@
data Writer w :: Effect where
  Tell :: w -> Writer w m ()
  Listen :: Eff (Writer w ': effs) a -> Writer w (Eff effs) (w, a)
  Censor :: (w -> w) -> Eff (Writer w ': effs) a -> Writer w (Eff effs) a

-- | Appends the given value to the current output.
tell :: Writer w :< effs => w -> Eff effs ()
tell :: w -> Eff effs ()
tell = Writer w (Eff effs) () -> Eff effs ()
forall (eff :: Effect) a (effs :: [Effect]).
(eff :< effs) =>
eff (Eff effs) a -> Eff effs a
send (Writer w (Eff effs) () -> Eff effs ())
-> (w -> Writer w (Eff effs) ()) -> w -> Eff effs ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. w -> Writer w (Eff effs) ()
forall w (m :: * -> *). w -> Writer w m ()
Tell

-- | Executes the given action and includes its output in the result.
listen :: Writer w :< effs => Eff (Writer w ': effs) a -> Eff effs (w, a)
listen :: Eff (Writer w : effs) a -> Eff effs (w, a)
listen = Writer w (Eff effs) (w, a) -> Eff effs (w, a)
forall (eff :: Effect) a (effs :: [Effect]).
(eff :< effs) =>
eff (Eff effs) a -> Eff effs a
send (Writer w (Eff effs) (w, a) -> Eff effs (w, a))
-> (Eff (Writer w : effs) a -> Writer w (Eff effs) (w, a))
-> Eff (Writer w : effs) a
-> Eff effs (w, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff (Writer w : effs) a -> Writer w (Eff effs) (w, a)
forall w (effs :: [Effect]) a.
Eff (Writer w : effs) a -> Writer w (Eff effs) (w, a)
Listen

-- | Executes the given action and modifies its output by applying the given
-- function.
censor :: Writer w :< effs => (w -> w) -> Eff (Writer w ': effs) a -> Eff effs a
censor :: (w -> w) -> Eff (Writer w : effs) a -> Eff effs a
censor w -> w
a Eff (Writer w : effs) a
b = Writer w (Eff effs) a -> Eff effs a
forall (eff :: Effect) a (effs :: [Effect]).
(eff :< effs) =>
eff (Eff effs) a -> Eff effs a
send (Writer w (Eff effs) a -> Eff effs a)
-> Writer w (Eff effs) a -> Eff effs a
forall a b. (a -> b) -> a -> b
$ (w -> w) -> Eff (Writer w : effs) a -> Writer w (Eff effs) a
forall w (effs :: [Effect]) a.
(w -> w) -> Eff (Writer w : effs) a -> Writer w (Eff effs) a
Censor w -> w
a Eff (Writer w : effs) a
b