packages feed

mini-0.1.0.0: Mini/Transformers/WriterT.hs

{-# LANGUAGE TupleSections #-}

-- | Extension of a monad with a write-only environment
module Mini.Transformers.WriterT (
  -- * Type
  WriterT,

  -- * Writing
  tell,

  -- * Runners
  runWriterT,
) where

import Control.Applicative (
  Alternative (
    empty,
    (<|>)
  ),
 )
import Control.Monad (
  ap,
  liftM,
 )
import Data.Functor (
  (<&>),
 )
import Mini.Transformers.Class (
  MonadTrans (
    lift
  ),
 )

{-
 - Type
 -}

{- | A monad with monoidal write-only type /w/, inner monad /m/, and return type
/a/
-}
newtype WriterT w m a = WriterT
  { runWriterT :: m (a, w)
  -- ^ Unwrap a 'WriterT'
  }

instance (Monad m, Monoid w) => Functor (WriterT w m) where
  fmap = liftM

instance (Monad m, Monoid w) => Applicative (WriterT w m) where
  pure = WriterT . pure . (,mempty)
  (<*>) = ap

instance (Monad m, Alternative m, Monoid w) => Alternative (WriterT w m) where
  empty = WriterT empty
  m <|> n = WriterT $ runWriterT m <|> runWriterT n

instance (Monad m, Monoid w) => Monad (WriterT w m) where
  m >>= k = WriterT $ do
    (a, w) <- runWriterT m
    (b, w') <- runWriterT (k a)
    pure (b, w <> w')

instance (Monoid w) => MonadTrans (WriterT w) where
  lift m = WriterT $ m <&> (,mempty)

{-
 - Writing
 -}

-- | Append the given value to the output
tell :: (Monad m) => w -> WriterT w m ()
tell = WriterT . pure . ((),)