{-# LANGUAGE TypeSynonymInstances #-} module Data.Group ( Group(..), groupSum ) where import Data.List ((\\)) import Data.Map (Map) import qualified Data.Map as M import Data.Set (Set) import qualified Data.Set as S -- | Group is monoid with invertibility -- But for our purposes we prefer two functions: `add` and `sub`. class Eq a => Group a where add :: a -> a -> a sub :: a -> a -> a zero :: a instance Eq a => Group [a] where add = (++) sub = (\\) zero = [] instance Ord a => Group (Set a) where add = S.union sub = S.difference zero = S.empty instance (Ord k, Group a) => Group (Map k a) where add = M.unionWith add sub = M.differenceWith sub' where sub' x y = if z == zero then Nothing else Just z where z = sub x y zero = M.empty -- | Sums list groupSum :: Group a => [a] -> a groupSum = foldr add zero