THEff-0.1.1.0: src/Control/THEff/Writer.hs
{-# OPTIONS_HADDOCK show-extensions #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
module Control.THEff.Writer (
-- * Overview
-- |
-- This version builds its output lazily; for a strict version with
-- the same interface, see "Control.THEff.Writer.Strict".
--
-- > {-# LANGUAGE KindSignatures #-}
-- > {-# LANGUAGE FlexibleInstances #-}
-- > {-# LANGUAGE MultiParamTypeClasses #-}
-- > {-# LANGUAGE TemplateHaskell #-}
-- >
-- > import Control.THEff
-- > import Control.THEff.Writer
-- > import Control.Monad(forM_)
-- > import Data.Monoid
-- >
-- > type IntAccum = Sum Int
-- >
-- > mkEff "StrWriter" ''Writer ''String ''NoEff
-- > mkEff "IntWriter" ''Writer ''IntAccum ''StrWriter
-- >
-- > main:: IO ()
-- > main = putStrLn $ uncurry (flip (++)) $ runStrWriter $ do
-- > tell "Result"
-- > (r, Sum v) <- runIntWriter $ do
-- > tell "="
-- > forM_ [1::Int .. 10]
-- > (tell . Sum)
-- > return (pi :: Float)
-- > return $ show $ r * fromIntegral v
--
-- __/Output :/__ Result=172.7876
--
-- Note that for the effect `Writer' `mkEff' generates unary function runEEEE. `mkEff' chooses
-- generation unary or binary function runEEEE based on number of arguments of effect function.
-- E.g. runEffWriter.
-- * Types and functions used in mkEff
Writer'
, Writer(..)
, WriterResT
, effWriter
, runEffWriter
-- * Functions that use this effect
, tell
) where
import Control.THEff
import Data.Monoid
-- | Actually, the effect type
-- - __/v/__ - Type - the parameter of the effect.
-- - __/e/__ - mkEff generated type.
data Writer' v e = Writer' v (() -> e)
-- | Type implements link in the chain of effects.
-- Constructors must be named __/{EffectName}{Outer|WriterAction|WriterResult}/__
-- and have a specified types of fields.
-- - __/m/__ - Or Monad (if use the 'Lift') or phantom type - stub (if used 'NoEff').
-- - __/o/__ - Type of outer effect.
-- - __/a/__ - The result of mkEff generated runEEEE... function.
data Writer (m:: * -> *) e o v a = WriterOuter (o m e)
| WriterAction (Writer' v e)
| WriterResult a
-- | Result type of runEEEE.
type WriterResT r v = (r, v)
-- | This function is used in the 'mkEff' generated runEEEE functions and typically
-- in effect action functions. Calling the effect action.
effWriter:: EffClass Writer' v e => Writer' v r -> Eff e r
effWriter (Writer' v g) = effAction $ \k -> Writer' v (k . g)
-- | The main function of the effect implementing.
-- This function is used in the 'mkEff' generated runEEEE functions.
runEffWriter :: forall (t :: * -> *) (u :: (* -> *) -> * -> *) (m :: * -> *)
z v (m1 :: * -> *) e (o :: (* -> *) -> * -> *) w a r. (Monad m, Monoid v) =>
(u t r -> (r -> m (WriterResT z v)) -> m (WriterResT z v)) -- ^ The outer effect function
-> (Writer m1 e o w a -> r) -- ^ The chain of effects link wrapper.
-> (r -> Writer t r u v z) -- ^ The chain of effects link unwrapper.
-- -> WriterArgT v -- unused argument!
-> Eff r a
-> m (WriterResT z v)
runEffWriter outer to un m = loop mempty $ runEff m (to . WriterResult)
where
loop s = select . un where
select (WriterOuter g) = outer g (loop s)
select (WriterAction (Writer' v k)) = let s' = s `mappend` v -- (f v)
in loop s' (k ())
select (WriterResult r) = return (r,s)
-- | Add value to monoid.
tell :: EffClass Writer' v e => v -> Eff e ()
tell v = effWriter $ Writer' v (const ())