module Data.Group.Free.Product
( FreeProduct(..)
, simplify
, coproduct
, injl
, injr
) where
import Data.Bifunctor
import Data.Group
import Data.Group.Order
import Data.Sequence (Seq(..))
import qualified Data.Sequence as Seq
newtype FreeProduct g h = FreeProduct { runFreeProduct :: Seq (Either g h) }
deriving (Show, Eq, Ord)
instance Functor (FreeProduct g) where
fmap f = FreeProduct . fmap (fmap f) . runFreeProduct
instance Bifunctor FreeProduct where
bimap f g = FreeProduct . fmap (bimap f g) . runFreeProduct
simplify :: (Eq g, Eq h, Monoid g, Monoid h) => FreeProduct g h -> FreeProduct g h
simplify (FreeProduct fp) = FreeProduct $ go fp
where
go (Left IdentityElem :<| ghs) = go ghs
go (Right IdentityElem :<| ghs) = go ghs
go (Left g :<| Left g' :<| ghs) = go $ Left (g <> g') :<| ghs
go (Right h :<| Right h' :<| ghs) = go $ Right (h <> h') :<| ghs
go (gh :<| ghs) = gh :<| go ghs
go Empty = Empty
instance Semigroup (FreeProduct g h) where
FreeProduct ghs <> FreeProduct ghs' = FreeProduct $ ghs <> ghs'
instance Monoid (FreeProduct g h) where
mempty = FreeProduct Seq.empty
instance (Group g, Group h) => Group (FreeProduct g h) where
invert (FreeProduct ghs) = FreeProduct $ bimap invert invert <$> Seq.reverse ghs
instance (GroupOrder g, GroupOrder h) => GroupOrder (FreeProduct g h) where
order = go . runFreeProduct . simplify
where
go Seq.Empty = Finite 1
go (x :<| Seq.Empty) = either order order x
go (Left g :<| (ghs :|> Left g'))
| g <> g' == mempty = go ghs
go (Right h :<| (ghs :|> Right h'))
| h <> h' == mempty = go ghs
go _ = Infinite
injl :: a -> FreeProduct a b
injl a = FreeProduct $ Seq.singleton (Left a)
injr :: b -> FreeProduct a b
injr b = FreeProduct $ Seq.singleton (Right b)
coproduct :: Monoid m => (a -> m) -> (b -> m) -> FreeProduct a b -> m
coproduct gi hi (FreeProduct ghs) = foldMap (either gi hi) ghs