packages feed

hs-ix-0.2.0.0: Control/Monad/Indexed/Trans/Writer.hs

-- | The indexed writer transformer: each @'WriterT' κ f@ term bears a morphism of @κ@ atop its argument, which are composed as the 'WriterT' terms are 'join'ed and @('<*>')@d.

module Control.Monad.Indexed.Trans.Writer where

import Prelude hiding ((.), id, (<*>), Monad (..))
import Control.Applicative (Alternative (..))
import qualified Control.Applicative as Base
import Control.Category (Category (id))
import Control.Semigroupoid (Semigroupoid (..))
import qualified Control.Monad as Base
import qualified Control.Monad.Fix as Base
import Control.Monad.Indexed.Signatures
import Data.Functor.Indexed

newtype WriterT κ f i j a = WriterT { runWriterT :: f (a, κ i j) }
  deriving (Foldable, Functor, Traversable)

lift :: (Functor f, Category κ) => f a -> WriterT κ f k k a
lift xm = WriterT $ flip (,) id <$> xm

mapWriterT :: (f (a, κ i j) -> f' (a', κ' i' j')) -> WriterT κ f i j a -> WriterT κ' f' i' j' a'
mapWriterT f = WriterT . f . runWriterT

tell :: Applicative p => κ i j -> WriterT κ p i j ()
tell = WriterT . pure . (,) ()

listen :: Functor f => WriterT κ f i j a -> WriterT κ f i j (a, κ i j)
listen = mapWriterT . fmap $ \ (a, v) -> ((a, v), v)

pass :: Functor f => WriterT κ f i j (a, κ i j -> κ i j) -> WriterT κ f i j a
pass = mapWriterT . fmap $ \ ((a, f), v) -> (a, f v)

censor :: Functor f => (κ i j -> κ' i' j') -> WriterT κ f i j a -> WriterT κ' f i' j' a
censor = mapWriterT . fmap . fmap

instance (Base.Applicative p, Category κ) => Base.Applicative (WriterT κ p k k) where
    pure = lift . pure
    (<*>) = (<*>)

instance (Base.Monad m, Category κ) => Base.Monad (WriterT κ m k k) where
    (>>=) = (>>=)

instance (Semigroupoid κ, Base.Applicative p) => Apply (WriterT κ p) where
    WriterT x <*> WriterT y = WriterT $ (\ (f, u) (a, v) -> (f a, v . u)) <$> x Base.<*> y

instance (Semigroupoid κ, Base.Monad m) => Bind (WriterT κ m) where
    join (WriterT x) = WriterT [(b, v . u) | (WriterT y, u) <- x, (b, v) <- y]

instance (Alternative p, Category κ) => Alternative (WriterT κ p k k) where
    empty = WriterT empty
    WriterT x <|> WriterT y = WriterT (x <|> y)

instance (Base.MonadPlus p, Category κ) => Base.MonadPlus (WriterT κ p k k)

instance (Base.MonadFix m, Category κ) => Base.MonadFix (WriterT κ m k k) where
    mfix f = WriterT $ Base.mfix (\ (a, u) -> (\ (b, v) -> (b, v . u)) <$> runWriterT (f a))

liftCallCC
 :: Category κ
 => CallCC f g h (a, κ k k) (b, κ i₁ j₁) (c, κ i₂ j₂) (d, κ i₃ j₃) -> CallCC (WriterT κ f i₁ j₁) (WriterT κ g i₂ j₂) (WriterT κ h i₃ j₃) a b c d
liftCallCC callCC f = WriterT $ callCC $ \ k -> runWriterT $ f $ \ a -> WriterT $ k (a, id)

liftCatch
 :: Catch e f g h (a, κ i₁ j₁) (b, κ i₂ j₂) (c, κ i₃ j₃)
 -> Catch e (WriterT κ f i₁ j₁) (WriterT κ g i₂ j₂) (WriterT κ h i₃ j₃) a b c
liftCatch catchE (WriterT xm) h = WriterT $ catchE xm $ runWriterT . h