{-# language RankNTypes #-}
{-# language Safe #-}
module Data.Group.Free.Church
(
FG(..)
, interpretFG
, reifyFG
, reflectFG
, presentFG
, FA(..)
, forgetFA
, interpretFA
, reifyFA
, reflectFA
) where
import Control.Applicative
import Control.Monad
import Data.Semigroup(Semigroup(..))
import Data.Group
import Data.Group.Free
import qualified Data.Map.Strict as Map
newtype FG a = FG { runFG :: forall g. Group g => (a -> g) -> g }
instance Semigroup (FG a) where
(FG g) <> (FG g') = FG $ \k -> g k <> g' k
instance Monoid (FG a) where
mempty = FG $ const mempty
instance Group (FG a) where
invert (FG g) = FG (invert . g)
instance Functor FG where
fmap f (FG fa) = FG $ \k -> fa (k . f)
instance Applicative FG where
pure a = FG ($ a)
(<*>) = ap
instance Monad FG where
return = pure
(FG fg) >>= f = FG $ \k -> fg (\a -> (runFG $ f a) k)
instance Alternative FG where
empty = mempty
(<|>) = (<>)
interpretFG :: Group g => FG g -> g
interpretFG (FG fg) = fg id
{-# inline interpretFG #-}
reifyFG :: FG a -> FreeGroup a
reifyFG fg = interpretFG $ fmap pure fg
{-# inline reifyFG #-}
reflectFG :: FreeGroup a -> FG a
reflectFG (FreeGroup fg) = FG $ \k -> foldMap (go k) fg
where
go k (Left a) = invert (k a)
go k (Right a) = k a
{-# inline reflectFG #-}
presentFG :: Group g => FG g -> (FG g -> g) -> g
presentFG = flip ($)
{-# inline presentFG #-}
newtype FA a = FA { runFA :: forall g. Abelian g => (a -> Integer -> g) -> g }
instance Semigroup (FA a) where
(FA g) <> (FA g') = FA $ \k -> g k <> g' k
stimes = gtimes
instance Monoid (FA a) where
mempty = FA $ const mempty
instance Group (FA a) where
invert g = pow g (-1 :: Integer)
pow (FA g) n
| n == 0 = mempty
| otherwise = FA $ \k -> g (\a i -> k a (toInteger n * i))
instance Abelian (FA a)
instance Functor FA where
fmap f (FA fa) = FA $ \k -> fa (k . f)
instance Applicative FA where
pure a = FA $ \k -> k a 1
(<*>) = ap
instance Monad FA where
return = pure
fa >>= f = interpretFA $ fmap f fa
instance Alternative FA where
empty = mempty
(<|>) = (<>)
interpretFA :: Abelian g => FA g -> g
interpretFA (FA fa) = fa pow
{-# inline interpretFA #-}
reifyFA :: Ord a => FA a -> FreeAbelianGroup a
reifyFA = interpretFA . fmap singleton
{-# inline reifyFA #-}
reflectFA :: FreeAbelianGroup a -> FA a
reflectFA fa =
let g = runFreeAbelianGroup fa
in FA $ \k -> Map.foldMapWithKey k g
{-# inline reflectFA #-}
forgetFA :: (Ord a) => FA a -> FG a
forgetFA fa = case reifyFA fa of
~(FreeAbelianGroup fa') -> FG $ \t -> Map.foldMapWithKey (\a n -> t a `pow` n) fa'
{-# inline forgetFA #-}