module Data.Monoid.Abelian
( FreeAbelianMonoid (..)
) where
import Data.Constraint (Dict (..))
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Semigroup (stimes)
import Data.Natural (Natural)
import Data.Algebra.Free (AlgebraType, AlgebraType0, FreeAlgebra (..), Proof (..))
import Data.Semigroup.Abelian (AbelianSemigroup)
newtype FreeAbelianMonoid a = FreeAbelianMonoid (Map a Natural)
deriving (Eq, Ord, Show)
instance Ord a => Semigroup (FreeAbelianMonoid a) where
(FreeAbelianMonoid a) <> (FreeAbelianMonoid b) = FreeAbelianMonoid $ Map.unionWith (+) a b
instance Ord a => AbelianSemigroup (FreeAbelianMonoid a)
instance Ord a => Monoid (FreeAbelianMonoid a) where
mempty = FreeAbelianMonoid (Map.empty)
type instance AlgebraType0 FreeAbelianMonoid a = Ord a
type instance AlgebraType FreeAbelianMonoid m = (Ord m, Monoid m, AbelianSemigroup m)
instance FreeAlgebra FreeAbelianMonoid where
returnFree a = FreeAbelianMonoid (Map.singleton a 1)
foldMapFree g (FreeAbelianMonoid as) = Map.foldMapWithKey (\a n -> stimes n $ g a) as
proof = Proof Dict
forget = Proof Dict