module Data.Monoid.Multiplicative 
    ( module Data.Monoid.Additive
    , MultiplicativeMonoid
    , one, times
    ) where

import Data.Monoid.Additive
import Data.FingerTree
import Data.Monoid.FromString
import Data.Monoid.Monad.Identity
import Data.Monoid.Generator
import qualified Data.Sequence as Seq
import Data.Sequence (Seq)

class MultiplicativeMonoid m where
    one :: m
    times :: m -> m -> m

instance Monoid m => MultiplicativeMonoid [m] where
    one = [mempty]
    xss `times` yss = [ xs `mappend` ys | xs <- xss, ys <- yss ]

instance (Measured v m, Monoid m) => MultiplicativeMonoid (FingerTree v m) where
    one = singleton mempty
    xss `times` yss = runIdentity $ mapReduce (flip fmap' yss . mappend) xss

instance (Monoid m) => MultiplicativeMonoid (Seq m) where
    one = Seq.singleton mempty
    xss `times` yss = runIdentity $ mapReduce (flip fmap yss . mappend) xss

instance MultiplicativeMonoid m => MultiplicativeMonoid (Identity m) where
    one = Identity one
    Identity a `times` Identity b = Identity (a `times` b)

instance MultiplicativeMonoid m => MultiplicativeMonoid (FromString m) where
    one = FromString one
    FromString a `times` FromString b = FromString (a `times` b)