module Data.Group 
    ( module Data.Monoid.Additive
    , Group
    , gnegate
    , minus
    ) where

import Data.Monoid.Additive
import Data.Monoid.Monad.Identity
import Data.Monoid.FromString

infixl 6 `minus`

class Monoid a => Group a where
    -- additive inverse
    gnegate :: a -> a

    -- right cancellation
    minus :: a -> a -> a
    a `minus` b = a `plus` gnegate b 

instance Num a => Group (Sum a) where
    gnegate = Sum . negate . getSum
    Sum a `minus` Sum b = Sum (a - b)
    
instance Fractional a => Group (Product a) where
    gnegate = Product . negate . getProduct
    Product a `minus` Product b = Product (a / b)
    
instance Group a => Group (Dual a) where
    gnegate = Dual . gnegate . getDual

instance Group a => Group (Identity a) where
    gnegate = Identity . gnegate . runIdentity
    Identity a `minus` Identity b = Identity (a `minus` b)

instance Group a => Group (FromString a) where
    gnegate = FromString . gnegate . getFromString
    FromString a `minus` FromString b = FromString (a `minus` b)