module Data.Monoid.Monad where

import qualified Data.Monoid.Transformer as MonoidTrans

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

{- |
Sequence actions and combine their monadic results with 'mappend'.

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


instance (Monad m, Semigroup a) => Semigroup (T m a) where
   Cons x <> Cons y = Cons $ liftM2 (<>) x y

instance (Monad m, Monoid a) => Monoid (T m a) where
   mempty = Cons $ return mempty
   mappend (Cons x) (Cons y) =
      Cons $ liftM2 mappend x y

instance (Monad m) => MonoidTrans.C (T m) where
   lift = Cons . return