module Data.Monoid.State where

import qualified Data.Monoid.Transformer as MonoidTrans
import Data.Monoid (Monoid, mempty, mappend, )

newtype T s a = Cons {run :: s -> (a,s)}

evaluate :: s -> T s a -> a
evaluate s m = fst $ run m s

execute :: s -> T s a -> s
execute s m = snd $ run m s


put :: Monoid a => s -> T s a
put s = Cons $ const (mempty, s)

modify :: Monoid a => (s -> s) -> T s a
modify f = Cons $ \s -> (mempty, f s)


instance Monoid a => Monoid (T s a) where
   mempty = MonoidTrans.lift mempty
   mappend (Cons x) (Cons y) =
      Cons $ \s0 ->
         let (xr,s1) = x s0
             (yr,s2) = y s1
         in  (mappend xr yr, s2)

instance MonoidTrans.C (T r) where
   lift x = Cons $ (,) x