data-category-0.9: Data/Category/KanExtension.hs
{-# LANGUAGE
FlexibleInstances
, GADTs
, MultiParamTypeClasses
, RankNTypes
, TypeOperators
, TypeFamilies
, UndecidableInstances
, NoImplicitPrelude
#-}
-----------------------------------------------------------------------------
-- |
-- Module : Data.Category.KanExtension
-- License : BSD-style (see the file LICENSE)
--
-- Maintainer : sjoerd@w3future.com
-- Stability : experimental
-- Portability : non-portable
-----------------------------------------------------------------------------
module Data.Category.KanExtension where
import Data.Category
import Data.Category.Functor
import Data.Category.NaturalTransformation
import Data.Category.Adjunction
import Data.Category.Limit
import Data.Category.Unit
-- | The right Kan extension of a functor @p@ for functors @f@ with codomain @k@.
type family RanFam (p :: *) (k :: * -> * -> *) (f :: *) :: *
type Ran p f = RanFam p (Cod f) f
-- | An instance of @HasRightKan p k@ says there are right Kan extensions for all functors with codomain @k@.
class (Functor p, Category k) => HasRightKan p k where
-- | 'ran' gives the defining natural transformation of the right Kan extension of @f@ along @p@.
ran :: p -> Obj (Nat (Dom p) k) f -> Nat (Dom p) k (RanFam p k f :.: p) f
-- | 'ranFactorizer' shows that this extension is universal.
ranFactorizer :: Nat (Dom p) k (h :.: p) f -> Nat (Cod p) k h (RanFam p k f)
ranF :: HasRightKan p k => p -> Obj (Nat (Dom p) k) f -> Obj (Nat (Cod p) k) (RanFam p k f)
ranF p f = ranF' (ran p f)
ranF' :: Nat (Dom p) k (RanFam p k f :.: p) f -> Obj (Nat (Cod p) k) (RanFam p k f)
ranF' (Nat (r :.: _) _ _) = natId r
data RanFunctor (p :: *) (k :: * -> * -> *) = RanFunctor p
instance HasRightKan p k => Functor (RanFunctor p k) where
type Dom (RanFunctor p k) = Nat (Dom p) k
type Cod (RanFunctor p k) = Nat (Cod p) k
type RanFunctor p k :% f = RanFam p k f
RanFunctor p % n = ranFactorizer (n . ran p (src n))
-- | The right Kan extension along @p@ is right adjoint to precomposition with @p@.
ranAdj :: forall p k. HasRightKan p k => p -> Adjunction (Nat (Dom p) k) (Nat (Cod p) k) (Precompose p k) (RanFunctor p k)
ranAdj p = mkAdjunctionTerm (Precompose p) (RanFunctor p) (\_ -> ranFactorizer) (ran p)
-- | The left Kan extension of a functor @p@ for functors @f@ with codomain @k@.
type family LanFam (p :: *) (k :: * -> * -> *) (f :: *) :: *
type Lan p f = LanFam p (Cod f) f
-- | An instance of @HasLeftKan p k@ says there are left Kan extensions for all functors with codomain @k@.
class (Functor p, Category k) => HasLeftKan p k where
-- | 'lan' gives the defining natural transformation of the left Kan extension of @f@ along @p@.
lan :: p -> Obj (Nat (Dom p) k) f -> Nat (Dom p) k f (LanFam p k f :.: p)
-- | 'lanFactorizer' shows that this extension is universal.
lanFactorizer :: Nat (Dom p) k f (h :.: p) -> Nat (Cod p) k (LanFam p k f) h
lanF :: HasLeftKan p k => p -> Obj (Nat (Dom p) k) f -> Obj (Nat (Cod p) k) (LanFam p k f)
lanF p f = lanF' (lan p f)
lanF' :: Nat (Dom p) k f (LanFam p k f :.: p) -> Obj (Nat (Cod p) k) (LanFam p k f)
lanF' (Nat _ (r :.: _) _) = natId r
data LanFunctor (p :: *) (k :: * -> * -> *) = LanFunctor p
instance HasLeftKan p k => Functor (LanFunctor p k) where
type Dom (LanFunctor p k) = Nat (Dom p) k
type Cod (LanFunctor p k) = Nat (Cod p) k
type LanFunctor p k :% f = LanFam p k f
LanFunctor p % n = lanFactorizer (lan p (tgt n) . n)
-- | The left Kan extension along @p@ is left adjoint to precomposition with @p@.
lanAdj :: forall p k. HasLeftKan p k => p -> Adjunction (Nat (Cod p) k) (Nat (Dom p) k) (LanFunctor p k) (Precompose p k)
lanAdj p = mkAdjunctionInit (LanFunctor p) (Precompose p) (lan p) (\_ -> lanFactorizer)
type instance RanFam (Const j Unit ()) k f = Const Unit k (LimitFam j k f)
-- | The right Kan extension of @f@ along a functor to the unit category is the limit of @f@.
instance HasLimits j k => HasRightKan (Const j Unit ()) k where
ran p f@Nat{} = let cone = limit f in Nat (Const (coneVertex cone) :.: p) (srcF f) (cone !)
ranFactorizer n@(Nat (h :.: _) f _) = let fact = limitFactorizer (constPrecompIn n) in Nat h (Const (tgt fact)) (\Unit -> fact)
type instance LanFam (Const j Unit ()) k f = Const Unit k (ColimitFam j k f)
-- | The left Kan extension of @f@ along a functor to the unit category is the colimit of @f@.
instance HasColimits j k => HasLeftKan (Const j Unit ()) k where
lan p f@Nat{} = let cocone = colimit f in Nat (srcF f) (Const (coconeVertex cocone) :.: p) (cocone !)
lanFactorizer n@(Nat f (h :.: _) _) = let fact = colimitFactorizer (constPrecompOut n) in Nat (Const (src fact)) h (\Unit -> fact)
type instance RanFam (Id j) k f = f
-- | Ran id = id
instance (Category j, Category k) => HasRightKan (Id j) k where
ran Id (Nat f _ _) = idPrecomp f
ranFactorizer n@(Nat (h :.: Id) _ _) = n . idPrecompInv h
type instance LanFam (Id j) k f = f
-- | Lan id = id
instance (Category j, Category k) => HasLeftKan (Id j) k where
lan Id (Nat f _ _) = idPrecompInv f
lanFactorizer n@(Nat _ (h :.: Id) _) = idPrecomp h . n
type instance RanFam (q :.: p) k f = RanFam q k (RanFam p k f)
-- | Ran (q . p) = Ran q . Ran p
instance (HasRightKan q k, HasRightKan p k) => HasRightKan (q :.: p) k where
ran (q :.: p) f = let ranp = ran p f in case ran q (ranF' ranp) of
ranq@(Nat (r :.: _) _ _) -> ranp . (ranq `o` natId p) . compAssocInv r q p
ranFactorizer n@(Nat (h :.: (q :.: p)) _ _) = ranFactorizer (ranFactorizer (n . compAssoc h q p))
type instance LanFam (q :.: p) k f = LanFam q k (LanFam p k f)
-- | Lan (q . p) = Lan q . Lan p
instance (HasLeftKan q k, HasLeftKan p k) => HasLeftKan (q :.: p) k where
lan (q :.: p) f = let lanp = lan p f in case lan q (lanF' lanp) of
lanq@(Nat _ (l :.: _) _) -> compAssoc l q p . (lanq `o` natId p) . lanp
lanFactorizer n@(Nat _ (h :.: (q :.: p)) _) = lanFactorizer (lanFactorizer (compAssocInv h q p . n))
newtype RanHask p f a = RanHask (forall c. Obj (Dom p) c -> Cod p a (p :% c) -> f :% c)
data RanHaskF p f = RanHaskF
instance Functor p => Functor (RanHaskF p f) where
type Dom (RanHaskF p f) = Cod p
type Cod (RanHaskF p f) = (->)
type RanHaskF p f :% a = RanHask p f a
RanHaskF % ab = \(RanHask r) -> RanHask (\c bpc -> r c (bpc . ab))
type instance RanFam (Any p) (->) f = RanHaskF p f
instance Functor p => HasRightKan (Any p) (->) where
ran (Any p) (Nat f _ _) = Nat (RanHaskF :.: Any p) f (\z (RanHask r) -> r z (p % z))
ranFactorizer (Nat (h :.: Any p) f n) = Nat h RanHaskF (\z hz -> RanHask (\c zpc -> n c ((h % zpc) hz)))
data LanHask p f a where
LanHask :: Obj (Dom p) c -> Cod p (p :% c) a -> f :% c -> LanHask p f a
data LanHaskF p f = LanHaskF
instance Functor p => Functor (LanHaskF p f) where
type Dom (LanHaskF p f) = Cod p
type Cod (LanHaskF p f) = (->)
type LanHaskF p f :% a = LanHask p f a
LanHaskF % ab = \(LanHask c pca fc) -> LanHask c (ab . pca) fc
type instance LanFam (Any p) (->) f = LanHaskF p f
instance Functor p => HasLeftKan (Any p) (->) where
lan (Any p) (Nat f _ _) = Nat f (LanHaskF :.: Any p) (\z fz -> LanHask z (p % z) fz)
lanFactorizer (Nat f (h :.: Any p) n) = Nat LanHaskF h (\z (LanHask c pcz fc) -> (h % pcz) (n c fc))