module Data.Monoid.Monad where

import qualified Data.Monoid.Transformer as MonoidTrans

import Control.Monad (liftM2, )
import Data.Monoid (Monoid, mempty, )
import Data.Semigroup (Semigroup, (<>), )

{- |
Sequence actions and combine their monadic results with '(<>)'.

This type could be omitted, if 'Monad' would be a sub-class of 'Applicative'.
-}
newtype T m a = Cons {forall (m :: * -> *) a. T m a -> m a
run :: m a}


instance (Monad m, Semigroup a) => Semigroup (T m a) where
   Cons m a
x <> :: T m a -> T m a -> T m a
<> Cons m a
y = m a -> T m a
forall (m :: * -> *) a. m a -> T m a
Cons (m a -> T m a) -> m a -> T m a
forall a b. (a -> b) -> a -> b
$ (a -> a -> a) -> m a -> m a -> m a
forall (m :: * -> *) a1 a2 r.
Monad m =>
(a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 a -> a -> a
forall a. Semigroup a => a -> a -> a
(<>) m a
x m a
y

instance (Monad m, Monoid a) => Monoid (T m a) where
   mempty :: T m a
mempty = m a -> T m a
forall (m :: * -> *) a. m a -> T m a
Cons (m a -> T m a) -> m a -> T m a
forall a b. (a -> b) -> a -> b
$ a -> m a
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
forall a. Monoid a => a
mempty

instance (Monad m) => MonoidTrans.C (T m) where
   lift :: forall m. Monoid m => m -> T m m
lift = m m -> T m m
forall (m :: * -> *) a. m a -> T m a
Cons (m m -> T m m) -> (m -> m m) -> m -> T m m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m -> m m
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return