{-# LANGUAGE FunctionalDependencies #-}
module Control.Category.FreeEff
( EffCategory (..)
, FreeEffCat (..)
, liftCat
, foldNatLift
, liftKleisli
) where
import Prelude hiding (id, (.))
import Control.Arrow (Kleisli (..))
import Control.Category (Category (..))
import Data.Functor.Identity (Identity (..))
import Control.Category.Free (Cat (..))
import Control.Algebra.Free2 (FreeAlgebra2 (..))
import Data.Algebra.Free (AlgebraType, AlgebraType0, proof)
class Category c => EffCategory c m | c -> m where
lift :: m (c a b) -> c a b
instance Monad m => EffCategory (Kleisli m) m where
lift m = Kleisli (\a -> m >>= \(Kleisli f) -> f a)
instance EffCategory (->) Identity where
lift = runIdentity
data FreeEffCat :: (* -> *) -> (k -> k -> *) -> k -> k -> * where
Base :: c a b -> FreeEffCat m c a b
Lift :: m (FreeEffCat m c a b) -> FreeEffCat m c a b
instance (Functor m, Category c) => Category (FreeEffCat m c) where
id = Base id
Base f . Base g = Base $ f . g
f . Lift mg = Lift $ (f .) <$> mg
Lift mf . g = Lift $ (. g) <$> mf
instance (Functor m, Category c) => EffCategory (FreeEffCat m c) m where
lift = Lift
type instance AlgebraType0 (FreeEffCat m) c = (Monad m, Category c)
type instance AlgebraType (FreeEffCat m) c = EffCategory c m
instance Monad m => FreeAlgebra2 (FreeEffCat m) where
liftFree2 = Base
foldNatFree2 nat (Base cab) = nat cab
foldNatFree2 nat (Lift mcab) = lift $ foldNatFree2 nat <$> mcab
codom2 = proof
forget2 = proof
liftCat :: Monad m => tr a b -> FreeEffCat m (Cat tr) a b
liftCat = liftFree2 . liftFree2
foldNatLift
:: (Monad m, EffCategory c m)
=> (forall x y. tr x y -> c x y)
-> FreeEffCat m (Cat tr) a b
-> c a b
foldNatLift nat = foldNatFree2 (foldNatFree2 nat)
liftKleisli :: Applicative m => (a -> b) -> Kleisli m a b
liftKleisli f = Kleisli (pure . f)