prob-fx-0.1.0.2: src/Effects/Writer.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{- | Writer effect.
-}
module Effects.Writer (
Writer(..)
, tell
, tellM
, handleWriter
, handleWriterM) where
import Prog ( discharge, Member(inj), Prog(..) )
import Model ( Model(..) )
-- | Writer effect for writing to a strean @w@
data Writer w a where
-- | Write to a stream @w@
Tell :: w -- ^ value to write
-> Writer w ()
-- | Wrapper for @Tell@
tell :: Member (Writer w) es => w -> Prog es ()
tell w = Op (inj $ Tell w) Val
-- | Wrapper for @Tell@ inside @Model@
tellM :: Member (Writer w) es => w -> Model env es ()
tellM w = Model $ tell w
-- | Handle the @Writer@ effect for a stream @w@
handleWriter :: forall w es a. Monoid w
=> Prog (Writer w ': es) a
-- | (output, final stream)
-> Prog es (a, w)
handleWriter = loop mempty where
loop :: w -> Prog (Writer w ': es) a -> Prog es (a, w)
loop w (Val x) = return (x, w)
loop w (Op u k) = case discharge u of
Right (Tell w') -> loop (w `mappend` w') (k ())
Left u' -> Op u' (loop w . k)
-- | Handle the @Writer@ effect inside a @Model@
handleWriterM :: Monoid w
=> Model env (Writer w : es) a
-- | (output, final stream)
-> Model env es (a, w)
handleWriterM m = Model $ handleWriter $ runModel m