data-category-0.11: Data/Category/WeightedLimit.hs
{-# LANGUAGE TypeOperators, RankNTypes, GADTs, TypeFamilies, MultiParamTypeClasses, FlexibleInstances, UndecidableInstances, NoImplicitPrelude, FlexibleContexts #-}
-----------------------------------------------------------------------------
-- |
-- Module : Data.Category.WeightedLimit
-- License : BSD-style (see the file LICENSE)
--
-- Maintainer : sjoerd@w3future.com
-- Stability : experimental
-- Portability : non-portable
-----------------------------------------------------------------------------
module Data.Category.WeightedLimit where
import Data.Kind (Type)
import Data.Category
import Data.Category.Functor
import Data.Category.Product
import Data.Category.NaturalTransformation
import qualified Data.Category.Limit as L
type WeightedCone w d e = forall a. Obj (Dom w) a -> w :% a -> Cod d e (d :% a)
-- | @w@-weighted limits in the category @k@.
class (Functor w, Cod w ~ (->), Category k) => HasWLimits k w where
type WeightedLimit k w d :: Type
limitObj :: FunctorOf (Dom w) k d => w -> d -> Obj k (WLimit w d)
limit :: FunctorOf (Dom w) k d => w -> d -> WeightedCone w d (WLimit w d)
limitFactorizer :: FunctorOf (Dom w) k d => w -> d -> Obj k e -> WeightedCone w d e -> k e (WLimit w d)
type WLimit w d = WeightedLimit (Cod d) w d
data LimitFunctor (k :: Type -> Type -> Type) w = LimitFunctor w
instance HasWLimits k w => Functor (LimitFunctor k w) where
type Dom (LimitFunctor k w) = Nat (Dom w) k
type Cod (LimitFunctor k w) = k
type LimitFunctor k w :% d = WeightedLimit k w d
LimitFunctor w % Nat d d' n = limitFactorizer w d' (limitObj w d) (\a wa -> n a . limit w d a wa)
-- | Regular limits as weigthed limits, weighted by the constant functor to '()'.
instance L.HasLimits j k => HasWLimits k (Const j (->) ()) where
type WeightedLimit k (Const j (->) ()) d = L.Limit d
limitObj Const{} d = L.coneVertex (L.limit (natId d))
limit Const{} d a () = L.limit (natId d) ! a
limitFactorizer Const{} d e f = L.limitFactorizer (Nat (Const e) d (`f` ()))
class Category v => HasEnds v where
type End (v :: Type -> Type -> Type) t :: Type
end :: FunctorOf (Op k :**: k) v t => t -> Obj v (End v t)
endCounit :: FunctorOf (Op k :**: k) v t => t -> Obj k a -> v (End v t) (t :% (a, a))
endFactorizer :: FunctorOf (Op k :**: k) v t => t -> (forall a. Obj k a -> v x (t :% (a, a))) -> v x (End v t)
-- | Ends as Hom-weighted limits
instance HasEnds k => HasWLimits k (Hom k) where
type WeightedLimit k (Hom k) d = End k d
limitObj Hom d = end d
limit Hom d (Op a :**: _) ab = d % (Op a :**: ab) . endCounit d a
limitFactorizer Hom d _ f = endFactorizer d (\a -> f (Op a :**: a) a)
data EndFunctor (k :: Type -> Type -> Type) (v :: Type -> Type -> Type) = EndFunctor
instance (HasEnds v, Category k) => Functor (EndFunctor k v) where
type Dom (EndFunctor k v) = Nat (Op k :**: k) v
type Cod (EndFunctor k v) = v
type EndFunctor k v :% t = End v t
EndFunctor % Nat f g n = endFactorizer g (\a -> n (Op a :**: a) . endCounit f a)
newtype HaskEnd t = HaskEnd { getHaskEnd :: forall k a. FunctorOf (Op k :**: k) (->) t => t -> Obj k a -> t :% (a, a) }
instance HasEnds (->) where
type End (->) t = HaskEnd t
end _ e = e
endCounit t a (HaskEnd f) = f t a
endFactorizer _ e x = HaskEnd (\_ a -> e a x)
type WeightedCocone w d e = forall a. Obj (Dom w) a -> w :% a -> Cod d (d :% a) e
-- | @w@-weighted colimits in the category @k@.
class (Functor w, Cod w ~ (->), Category k) => HasWColimits k w where
type WeightedColimit k w d :: Type
colimitObj :: (FunctorOf j k d, Op j ~ Dom w) => w -> d -> Obj k (WColimit w d)
colimit :: (FunctorOf j k d, Op j ~ Dom w) => w -> d -> WeightedCocone w d (WColimit w d)
colimitFactorizer :: (FunctorOf j k d, Op j ~ Dom w) => w -> d -> Obj k e -> WeightedCocone w d e -> k (WColimit w d) e
type WColimit w d = WeightedColimit (Cod d) w d
data ColimitFunctor (k :: Type -> Type -> Type) w = ColimitFunctor w
instance (Functor w, Category k, HasWColimits k (w :.: OpOp (Dom w))) => Functor (ColimitFunctor k w) where
type Dom (ColimitFunctor k w) = Nat (Op (Dom w)) k
type Cod (ColimitFunctor k w) = k
type ColimitFunctor k w :% d = WeightedColimit k (w :.: OpOp (Dom w)) d
ColimitFunctor w % Nat d d' n = colimitFactorizer (w :.: OpOp) d (colimitObj (w :.: OpOp) d') (\(Op a) wa -> colimit (w :.: OpOp) d' (Op a) wa . n a)
-- | Regular colimits as weigthed colimits, weighted by the constant functor to '()'.
instance L.HasColimits j k => HasWColimits k (Const (Op j) (->) ()) where
type WeightedColimit k (Const (Op j) (->) ()) d = L.Colimit d
colimitObj (Const _) d = L.coconeVertex (L.colimit (natId d))
colimit (Const _) d (Op a) () = L.colimit (natId d) ! a
colimitFactorizer (Const _) d e f = L.colimitFactorizer (Nat d (Const e) (\z -> f (Op z) ()))
class Category v => HasCoends v where
type Coend (v :: Type -> Type -> Type) t :: Type
coend :: FunctorOf (Op k :**: k) v t => t -> Obj v (Coend v t)
coendCounit :: FunctorOf (Op k :**: k) v t => t -> Obj k a -> v (t :% (a, a)) (Coend v t)
coendFactorizer :: FunctorOf (Op k :**: k) v t => t -> (forall a. Obj k a -> v (t :% (a, a)) x) -> v (Coend v t) x
data OpHom (k :: Type -> Type -> Type) = OpHom
-- | The Hom-functor but with opposite domain.
instance Category k => Functor (OpHom k) where
type Dom (OpHom k) = Op (Op k :**: k)
type Cod (OpHom k) = (->)
type OpHom k :% (a1, a2) = k a2 a1
OpHom % Op (Op f1 :**: f2) = \g -> f1 . g . f2
-- | Coends as OpHom-weighted colimits
instance HasCoends k => HasWColimits k (OpHom k) where
type WeightedColimit k (OpHom k) d = Coend k d
colimitObj OpHom d = coend d
colimit OpHom d (Op (Op a :**: _)) ab = coendCounit d a . d % (Op a :**: ab)
colimitFactorizer OpHom d _ f = coendFactorizer d (\a -> f (Op (Op a :**: a)) a)
data CoendFunctor (k :: Type -> Type -> Type) (v :: Type -> Type -> Type) = CoendFunctor
instance (HasCoends v, Category k) => Functor (CoendFunctor k v) where
type Dom (CoendFunctor k v) = Nat (Op k :**: k) v
type Cod (CoendFunctor k v) = v
type CoendFunctor k v :% t = Coend v t
CoendFunctor % Nat f g n = coendFactorizer f (\a -> coendCounit g a . n (Op a :**: a))
data HaskCoend t where
HaskCoend :: FunctorOf (Op k :**: k) (->) t => t -> Obj k a -> t :% (a, a) -> HaskCoend t
instance HasCoends (->) where
type Coend (->) t = HaskCoend t
coend _ e = e
coendCounit t a taa = HaskCoend t a taa
coendFactorizer _ f (HaskCoend _ a taa) = f a taa