Numbers are monoidal in two ways: addition with 0 as the unit, and multiplication with 1 as the unit. Both are equally valid and useful in different circumstances. So rather than choose a preferred instance for numbers, there are two newtypes
, Sum
and Product
to tag them for the different functionality.
newtype Sum n = Sum { getSum :: n }
instance Num n => Monoid (Sum n) where
mempty = Sum 0
Sum x `mappend` Sum y = Sum (x + y)
newtype Product n = Product { getProduct :: n }
instance Num n => Monoid (Product n) where
mempty = Product 1
Product x `mappend` Product y = Product (x * y)
This effectively allows for the developer to choose which functionality to use by wrapping the value in the appropriate newtype
.
Sum 3 <> Sum 5 == Sum 8
Product 3 <> Product 5 == Product 15