{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances #-} ----------------------------------------------------------------------------- -- | -- Module : Data.Monoid.Multiplicative -- Copyright : (c) Edward Kmett 2009 -- License : BSD-style -- Maintainer : ekmett@gmail.com -- Stability : experimental -- Portability : portable (but instances use MPTCs) -- -- When dealing with a 'Ring' or other structure, you often need a pair of -- 'Monoid' instances that are closely related. Making a @newtype@ for one -- is unsatisfying and yields an unnatural programming style. -- -- A 'Multiplicative' is a 'Monoid' that is intended for use in a scenario -- that can be extended to have another 'Monoid' slot in for addition. This -- enables one to use common notation. -- -- Any 'Multiplicative' can be turned into a 'Monoid' using the 'Log' wrapper. -- -- Any 'Monoid' can be turned into a 'Multiplicative' using the 'Exp' wrapper. -- -- Instances are supplied for common Monads of Monoids, in a fashion -- which can be extended if the 'Monad' is a 'MonadPlus' to yield a 'LeftSemiNearRing' -- -- Instances are also supplied for common Applicatives of Monoids, in a -- fashion which can be extended if the 'Applicative' is 'Alternative' to -- yield a 'LeftSemiNearRing' ----------------------------------------------------------------------------- module Data.Monoid.Multiplicative ( module Data.Monoid.Additive -- * Multiplicative Monoids , Multiplicative , one, times -- * Multiplicative to Monoid , Log(Log, getLog) -- * Monoid to Multiplicative , Exp(Exp, getExp) ) where import Control.Applicative import Control.Concurrent.STM import Control.Monad.Cont import Control.Monad.Identity import Control.Monad.Reader import qualified Control.Monad.RWS.Lazy as LRWS import qualified Control.Monad.RWS.Strict as SRWS import qualified Control.Monad.State.Lazy as LState import qualified Control.Monad.State.Strict as SState import qualified Control.Monad.Writer.Lazy as LWriter import qualified Control.Monad.Writer.Strict as SWriter import qualified Control.Monad.ST.Lazy as LST import qualified Control.Monad.ST.Strict as SST import Data.FingerTree import Data.Monoid.Additive import Data.Monoid.FromString import Data.Monoid.Generator import Data.Monoid.Instances () import Data.Monoid.Self import Data.Ratio import qualified Data.Sequence as Seq import Data.Sequence (Seq) import Text.Parsec.Prim class Multiplicative m where one :: m times :: m -> m -> m -- | Convert a 'Multiplicative' into a 'Monoid'. Mnemonic: @Log a + Log b = Log (a * b)@ data Log m = Log { getLog :: m } instance Multiplicative m => Monoid (Log m) where mempty = Log one Log a `mappend` Log b = Log (a `times` b) -- | Convert a 'Monoid' into a 'Multiplicative'. Mnemonic: @Exp a * Exp b = Exp (a + b)@ data Exp m = Exp { getExp :: m } instance Monoid m => Multiplicative (Exp m) where one = Exp mempty Exp a `times` Exp b = Exp (a `mappend` b) -- simple monoid transformer instances instance Multiplicative m => Multiplicative (Self m) where one = Self one Self a `times` Self b = Self (a `times` b) instance Multiplicative m => Multiplicative (FromString m) where one = FromString one FromString a `times` FromString b = FromString (a `times` b) -- the goal of this is that I can make left seminearrings out of any 'Alternative' wrapped around a monoid -- in particular its useful for containers instance Monoid m => Multiplicative [m] where one = return mempty times = liftM2 mappend instance Monoid m => Multiplicative (Seq m) where one = return mempty times = liftM2 mappend -- and things that can't quite be a Monad in Haskell instance (Measured v m, Monoid m) => Multiplicative (FingerTree v m) where one = singleton mempty xss `times` yss = getSelf $ mapReduce (flip fmap' yss . mappend) xss -- but it can at least serve as a canonical multiplication for any monad. instance Monoid m => Multiplicative (Maybe m) where one = return mempty times = liftM2 mappend instance Monoid m => Multiplicative (Identity m) where one = return mempty times = liftM2 mappend instance (Monoid m) => Multiplicative (Cont r m) where one = return mempty times = liftM2 mappend instance (Monoid w, Monoid m) => Multiplicative (SRWS.RWS r w s m) where one = return mempty times = liftM2 mappend instance (Monoid w, Monoid m) => Multiplicative (LRWS.RWS r w s m) where one = return mempty times = liftM2 mappend instance Monoid m => Multiplicative (SState.State s m) where one = return mempty times = liftM2 mappend instance Monoid m => Multiplicative (LState.State s m) where one = return mempty times = liftM2 mappend instance Monoid m => Multiplicative (Reader e m) where one = return mempty times = liftM2 mappend instance (Monoid w, Monoid m) => Multiplicative (SWriter.Writer w m) where one = return mempty times = liftM2 mappend instance (Monoid w, Monoid m) => Multiplicative (LWriter.Writer w m) where one = return mempty times = liftM2 mappend instance (Monad m, Monoid n) => Multiplicative (ContT r m n) where one = return mempty times = liftM2 mappend instance (Monad m, Monoid w, Monoid n) => Multiplicative (SRWS.RWST r w s m n) where one = return mempty times = liftM2 mappend instance (Monad m, Monoid w, Monoid n) => Multiplicative (LRWS.RWST r w s m n) where one = return mempty times = liftM2 mappend instance (Monad m, Monoid n) => Multiplicative (SState.StateT s m n) where one = return mempty times = liftM2 mappend instance (Monad m, Monoid n) => Multiplicative (LState.StateT s m n) where one = return mempty times = liftM2 mappend instance (Monad m, Monoid n) => Multiplicative (ReaderT e m n) where one = return mempty times = liftM2 mappend instance (Monad m, Monoid w, Monoid n) => Multiplicative (SWriter.WriterT w m n) where one = return mempty times = liftM2 mappend instance (Monad m, Monoid w, Monoid n) => Multiplicative (LWriter.WriterT w m n) where one = return mempty times = liftM2 mappend instance Monoid n => Multiplicative (IO n) where one = return mempty times = liftM2 mappend instance Monoid n => Multiplicative (SST.ST s n) where one = return mempty times = liftM2 mappend instance Monoid n => Multiplicative (LST.ST s n) where one = return mempty times = liftM2 mappend instance Monoid n => Multiplicative (STM n) where one = return mempty times = liftM2 mappend instance (Stream s m t, Monoid n) => Multiplicative (ParsecT s u m n) where one = return mempty times = liftM2 mappend -- Applicative instances instance Monoid n => Multiplicative (ZipList n) where one = pure mempty times = liftA2 mappend instance Monoid m => Multiplicative (Const m a) where one = pure undefined times = liftA2 undefined -- Numeric instances instance Multiplicative Int where one = 1 times = (*) instance Multiplicative Integer where one = 1 times = (*) instance Integral m => Multiplicative (Ratio m) where one = 1 times = (*)