{-# LANGUAGE CPP #-}
-- |
-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
-- License    : BSD3
-- Maintainer : ivan.perez@keera.co.uk
--
-- 'MSF's with a 'Writer' monadic layer.
--
-- This module contains functions to work with 'MSF's that include a 'Writer'
-- monadic layer. This includes functions to create new 'MSF's that include an
-- additional layer, and functions to flatten that layer out of the 'MSF`'s
-- transformer stack.
--
-- It is based on the _strict_ writer monad 'Control.Monad.Trans.Writer.Strict',
-- so when combining it with other modules such as @mtl@'s,
-- the strict version has to be included, i.e. 'Control.Monad.Writer.Strict'
-- instead of 'Control.Monad.Writer' or 'Control.Monad.Writer.Lazy'.
module Control.Monad.Trans.MSF.Writer
    ( module Control.Monad.Trans.Writer.Strict
    -- * 'Writer' 'MSF' running and wrapping
    , writerS
    , runWriterS
    )
  where

-- External imports
import Control.Monad.Trans.Writer.Strict hiding (liftCallCC, liftCatch, pass)

#if !MIN_VERSION_base(4,8,0)
import Data.Functor ((<$>))
import Data.Monoid  (Monoid)
#endif

-- Internal imports
import Data.MonadicStreamFunction (MSF, morphGS)

-- * 'Writer' 'MSF' running and wrapping

-- | Build an 'MSF' in the 'Writer' monad from one that produces the log as an
-- extra output. This is the opposite of 'runWriterS'.
writerS :: (Functor m, Monad m, Monoid w)
        => MSF m a (w, b) -> MSF (WriterT w m) a b
writerS :: forall (m :: * -> *) w a b.
(Functor m, Monad m, Monoid w) =>
MSF m a (w, b) -> MSF (WriterT w m) a b
writerS = (forall c. (a -> m ((w, b), c)) -> a -> WriterT w m (b, c))
-> MSF m a (w, b) -> MSF (WriterT w m) a b
forall (m2 :: * -> *) a1 (m1 :: * -> *) b1 a2 b2.
Monad m2 =>
(forall c. (a1 -> m1 (b1, c)) -> a2 -> m2 (b2, c))
-> MSF m1 a1 b1 -> MSF m2 a2 b2
morphGS ((forall c. (a -> m ((w, b), c)) -> a -> WriterT w m (b, c))
 -> MSF m a (w, b) -> MSF (WriterT w m) a b)
-> (forall c. (a -> m ((w, b), c)) -> a -> WriterT w m (b, c))
-> MSF m a (w, b)
-> MSF (WriterT w m) a b
forall a b. (a -> b) -> a -> b
$ \a -> m ((w, b), c)
f a
a -> m ((b, c), w) -> WriterT w m (b, c)
forall w (m :: * -> *) a. m (a, w) -> WriterT w m a
WriterT (m ((b, c), w) -> WriterT w m (b, c))
-> m ((b, c), w) -> WriterT w m (b, c)
forall a b. (a -> b) -> a -> b
$ (\((w
w, b
b), c
c) -> ((b
b, c
c), w
w)) (((w, b), c) -> ((b, c), w)) -> m ((w, b), c) -> m ((b, c), w)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> m ((w, b), c)
f a
a

-- | Build an 'MSF' that produces the log as an extra output from one on the
-- 'Writer' monad. This is the opposite of 'writerS'.
runWriterS :: (Functor m, Monad m)
           => MSF (WriterT s m) a b -> MSF m a (s, b)
runWriterS :: forall (m :: * -> *) s a b.
(Functor m, Monad m) =>
MSF (WriterT s m) a b -> MSF m a (s, b)
runWriterS = (forall c. (a -> WriterT s m (b, c)) -> a -> m ((s, b), c))
-> MSF (WriterT s m) a b -> MSF m a (s, b)
forall (m2 :: * -> *) a1 (m1 :: * -> *) b1 a2 b2.
Monad m2 =>
(forall c. (a1 -> m1 (b1, c)) -> a2 -> m2 (b2, c))
-> MSF m1 a1 b1 -> MSF m2 a2 b2
morphGS ((forall c. (a -> WriterT s m (b, c)) -> a -> m ((s, b), c))
 -> MSF (WriterT s m) a b -> MSF m a (s, b))
-> (forall c. (a -> WriterT s m (b, c)) -> a -> m ((s, b), c))
-> MSF (WriterT s m) a b
-> MSF m a (s, b)
forall a b. (a -> b) -> a -> b
$ \a -> WriterT s m (b, c)
f a
a -> (\((b
b, c
c), s
s) -> ((s
s, b
b), c
c))
         (((b, c), s) -> ((s, b), c)) -> m ((b, c), s) -> m ((s, b), c)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> WriterT s m (b, c) -> m ((b, c), s)
forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
runWriterT (a -> WriterT s m (b, c)
f a
a)