reducers-3.0: src/Data/Semigroup/Monad.hs
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts, TypeOperators #-}
-----------------------------------------------------------------------------
-- |
-- Module : Data.Semigroup.Monad
-- Copyright : (c) Edward Kmett 2009
-- License : BSD-style
-- Maintainer : ekmett@gmail.com
-- Stability : experimental
-- Portability : non-portable (MPTCs)
--
-- Semigroups for working with 'Monad's.
--
-----------------------------------------------------------------------------
module Data.Semigroup.Monad
( Action(..)
, Mon(..)
) where
import Control.Monad (liftM, liftM2)
import Data.Monoid (Monoid(..))
import Data.Semigroup (Semigroup(..))
import Data.Semigroup.Reducer (Reducer(..))
-- | A 'Action' uses an glues together monadic actions with (>>)
-- in the manner of 'mapM_' from "Data.Foldable". Any values returned by
-- reduced actions are discarded.
newtype Action f = Action { getAction :: f () }
instance Monad f => Semigroup (Action f) where
Action a <> Action b = Action (a >> b)
instance Monad f => Monoid (Action f) where
mempty = Action (return ())
Action a `mappend` Action b = Action (a >> b)
instance Monad f => Reducer (f a) (Action f) where
unit a = Action (a >> return ())
a `cons` Action b = Action (a >> b)
Action a `snoc` b = Action (a >> b >> return ())
-- | Efficiently avoid needlessly rebinding when using 'snoc' on an action that already returns ()
-- A rewrite rule automatically applies this when possible
snocAction :: Reducer (f ()) (Action f) => Action f -> f () -> Action f
snocAction a = (<>) a . Action
{-# RULES "unitAction" unit = Action #-}
{-# RULES "snocAction" snoc = snocAction #-}
newtype Mon f m = Mon { getMon :: f m }
deriving (Monad)
instance (Monad f, Semigroup m) => Semigroup (Mon f m) where
(<>) = liftM2 (<>)
instance (Monad f, Monoid m) => Monoid (Mon f m) where
mempty = return mempty
mappend = liftM2 mappend
instance (Monad f, Reducer c m) => Reducer (f c) (Mon f m) where
unit = liftM unit . Mon