{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_HADDOCK show-extensions #-}
module Control.Category.FreeEffect
( EffectCategory (..)
, EffCat (..)
, liftEffect
, foldNatEffCat
, liftKleisli
) where
import Prelude hiding (id, (.))
import Control.Arrow (Kleisli (..))
import Control.Category (Category (..))
import Data.Functor.Identity (Identity (..))
import Control.Algebra.Free2 (FreeAlgebra2 (..))
import Data.Algebra.Free (AlgebraType, AlgebraType0, Proof (..))
class Category c => EffectCategory c m | c -> m where
effect :: m (c a b) -> c a b
instance Monad m => EffectCategory (Kleisli m) m where
effect m = Kleisli (\a -> m >>= \(Kleisli f) -> f a)
instance EffectCategory (->) Identity where
effect = runIdentity
data EffCat :: (* -> *) -> (k -> k -> *) -> k -> k -> * where
Base :: c a b -> EffCat m c a b
Effect :: m (EffCat m c a b) -> EffCat m c a b
instance (Functor m, Category c) => Category (EffCat m c) where
id = Base id
Base f . Base g = Base $ f . g
f . Effect mg = Effect $ (f .) <$> mg
Effect mf . g = Effect $ (. g) <$> mf
instance (Functor m, Category c) => EffectCategory (EffCat m c) m where
effect = Effect
type instance AlgebraType0 (EffCat m) c = (Monad m, Category c)
type instance AlgebraType (EffCat m) c = EffectCategory c m
instance Monad m => FreeAlgebra2 (EffCat m) where
liftFree2 = Base
foldNatFree2 nat (Base cab) = nat cab
foldNatFree2 nat (Effect mcab) = effect $ foldNatFree2 nat <$> mcab
codom2 = Proof
forget2 = Proof
liftEffect :: ( Monad m
, FreeAlgebra2 cat
, AlgebraType0 cat tr
, Category (cat tr)
)
=> tr a b -> EffCat m (cat tr) a b
liftEffect = liftFree2 . liftFree2
foldNatEffCat
:: ( Monad m
, FreeAlgebra2 cat
, AlgebraType cat c
, AlgebraType0 cat tr
, Category (cat tr)
, EffectCategory c m
)
=> (forall x y. tr x y -> c x y)
-> EffCat m (cat tr) a b
-> c a b
foldNatEffCat nat = foldNatFree2 (foldNatFree2 nat)
liftKleisli :: Applicative m => (a -> b) -> Kleisli m a b
liftKleisli f = Kleisli (pure . f)