{- | An effect allowing writes to an accumulated quantity alongside a computed value,
and reads from the accumulator.
An 'Accum' @w@ effect keeps track of a monoidal datum of type @w@ and strictly appends to that monoidal value with the 'add' effect.
Previous writes to that value can be read with the 'look' effect.

Predefined carriers:

* "Control.Carrier.Accum.Church"
* "Control.Carrier.Accum.Strict". (A lazy carrier is not provided due to the inherent space leaks associated with lazy accumulation monads, similar to lazy writer monads.)
* "Control.Monad.Trans.Accum"

If 'Accum' @w@ is the last effect in a stack, it can be interpreted to a function @w -> (w, a)@ given some result type @a@ and the presence of a 'Monoid' instance for @w@.

-- | @since 1.1.2.0
-}

module Control.Effect.Accum
( -- * Accumulation effect
  Accum(..)
, add
, look
, looks
  -- * Re-exports
, Algebra
, Has
, run
) where

import Control.Algebra
import Control.Effect.Accum.Internal (Accum(..))


-- | Write a value to the log.
--
-- @
-- 'runAccum' w0 ('add' w '>>' m) = 'Data.Bifunctor.first' ('mappend' w) '<$>' 'runAccum' w0 m
-- 'runAccum' w0 ('add' w '>>' m) = runAccum (w0 <> w) m
-- @
--
-- @since 1.1.2.0
add :: Has (Accum w) sig m => w -> m ()
add :: forall w (sig :: (* -> *) -> * -> *) (m :: * -> *).
Has (Accum w) sig m =>
w -> m ()
add w
w = forall (eff :: (* -> *) -> * -> *) (sig :: (* -> *) -> * -> *)
       (m :: * -> *) a.
(Member eff sig, Algebra sig m) =>
eff m a -> m a
send (forall w (m :: * -> *). w -> Accum w m ()
Add w
w)
{-# INLINE add #-}

-- | Look up the previous accumulation
--
-- @
-- 'runAccum' w 'look' = 'return' (w, w)
-- 'runAccum' w ('look' >>= continuation) = 'runAccum' w (continuation w)
-- @
--
-- @since 1.1.2.0
look :: Has (Accum w) sig m => m w
look :: forall w (sig :: (* -> *) -> * -> *) (m :: * -> *).
Has (Accum w) sig m =>
m w
look = forall (eff :: (* -> *) -> * -> *) (sig :: (* -> *) -> * -> *)
       (m :: * -> *) a.
(Member eff sig, Algebra sig m) =>
eff m a -> m a
send forall w (m :: * -> *). Accum w m w
Look
{-# INLINE look #-}

-- | Look up the previous accumulation and apply a function to it.
--
-- @
-- looks f = fmap f look
-- @
--
-- @since 1.1.2.0
looks :: Has (Accum w) sig m => (w -> a) -> m a
looks :: forall w (sig :: (* -> *) -> * -> *) (m :: * -> *) a.
Has (Accum w) sig m =>
(w -> a) -> m a
looks w -> a
f = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap w -> a
f forall w (sig :: (* -> *) -> * -> *) (m :: * -> *).
Has (Accum w) sig m =>
m w
look
{-# INLINE looks #-}