{-# LANGUAGE
TypeOperators
, TypeFamilies
, GADTs
, RankNTypes
, FlexibleContexts
, NoImplicitPrelude
, UndecidableInstances
, ScopedTypeVariables
, ConstraintKinds
, AllowAmbiguousTypes
, TypeApplications
#-}
module Data.Category.Enriched where
import Data.Category (Category(..), Obj, Op(..))
import Data.Category.Product
import Data.Category.Functor (Functor(..), Hom(..), (:*-:), homX_)
import Data.Category.Limit hiding (HasLimits)
import Data.Category.CartesianClosed
import Data.Category.Boolean
class CartesianClosed (V k) => ECategory (k :: * -> * -> *) where
type V k :: * -> * -> *
type k $ ab :: *
hom :: Obj k a -> Obj k b -> Obj (V k) (k $ (a, b))
id :: Obj k a -> Arr k a a
comp :: Obj k a -> Obj k b -> Obj k c -> V k (BinaryProduct (V k) (k $ (b, c)) (k $ (a, b))) (k $ (a, c))
type Elem k = TerminalObject (V k) :*-: (V k)
elem :: CartesianClosed (V k) => Elem k
elem = homX_ terminalObject
type Arr k a b = Elem k :% (k $ (a, b))
compArr :: ECategory k => Obj k a -> Obj k b -> Obj k c -> Arr k b c -> Arr k a b -> Arr k a c
compArr a b c f g = comp a b c . (f &&& g)
data Underlying k a b = Underlying (Obj k a) (Arr k a b) (Obj k b)
instance ECategory k => Category (Underlying k) where
src (Underlying a _ _) = Underlying a (id a) a
tgt (Underlying _ _ b) = Underlying b (id b) b
Underlying b f c . Underlying a g _ = Underlying a (compArr a b c f g) c
newtype EOp k a b = EOp (k b a)
instance ECategory k => ECategory (EOp k) where
type V (EOp k) = V k
type EOp k $ (a, b) = k $ (b, a)
hom (EOp a) (EOp b) = hom b a
id (EOp a) = id a
comp (EOp a) (EOp b) (EOp c) = comp c b a . (proj2 (hom c b) (hom b a) &&& proj1 (hom c b) (hom b a))
data (:<>:) :: (* -> * -> *) -> (* -> * -> *) -> * -> * -> * where
(:<>:) :: (V k1 ~ V k2) => Obj k1 a1 -> Obj k2 a2 -> (:<>:) k1 k2 (a1, a2) (a1, a2)
instance (ECategory k1, ECategory k2, V k1 ~ V k2) => ECategory (k1 :<>: k2) where
type V (k1 :<>: k2) = V k1
type (k1 :<>: k2) $ ((a1, a2), (b1, b2)) = BinaryProduct (V k1) (k1 $ (a1, b1)) (k2 $ (a2, b2))
hom (a1 :<>: a2) (b1 :<>: b2) = hom a1 b1 *** hom a2 b2
id (a1 :<>: a2) = id a1 &&& id a2
comp (a1 :<>: a2) (b1 :<>: b2) (c1 :<>: c2) =
comp a1 b1 c1 . (proj1 bc1 bc2 . proj1 l r &&& proj1 ab1 ab2 . proj2 l r) &&&
comp a2 b2 c2 . (proj2 bc1 bc2 . proj1 l r &&& proj2 ab1 ab2 . proj2 l r)
where
ab1 = hom a1 b1
ab2 = hom a2 b2
bc1 = hom b1 c1
bc2 = hom b2 c2
l = bc1 *** bc2
r = ab1 *** ab2
newtype Self v a b = Self { getSelf :: v a b }
instance CartesianClosed v => ECategory (Self v) where
type V (Self v) = v
type Self v $ (a, b) = Exponential v a b
hom (Self a) (Self b) = ExpFunctor % (Op a :**: b)
id (Self a) = toSelf a
comp (Self a) (Self b) (Self c) = curry (bc *** ab) a c (apply b c . (proj1 bc ab *** apply a b) . shuffle)
where
bc = c ^^^ b
ab = b ^^^ a
shuffle = proj1 (bc *** ab) a &&& (proj2 bc ab *** a)
toSelf :: CartesianClosed v => v a b -> Arr (Self v) a b
toSelf v = curry terminalObject (src v) (tgt v) (v . proj2 terminalObject (src v))
fromSelf :: forall v a b. CartesianClosed v => Obj v a -> Obj v b -> Arr (Self v) a b -> v a b
fromSelf a b arr = uncurry terminalObject a b arr . (terminate a &&& a)
newtype InHask k a b = InHask (k a b)
instance Category k => ECategory (InHask k) where
type V (InHask k) = (->)
type InHask k $ (a, b) = k a b
hom (InHask a) (InHask b) = Hom % (Op a :**: b)
id (InHask f) () = f
comp _ _ _ (f, g) = f . g
class (ECategory (EDom ftag), ECategory (ECod ftag), V (EDom ftag) ~ V (ECod ftag)) => EFunctor ftag where
type EDom ftag :: * -> * -> *
type ECod ftag :: * -> * -> *
type ftag :%% a :: *
(%%) :: ftag -> Obj (EDom ftag) a -> Obj (ECod ftag) (ftag :%% a)
map :: (EDom ftag ~ k) => ftag -> Obj k a -> Obj k b -> V k (k $ (a, b)) (ECod ftag $ (ftag :%% a, ftag :%% b))
type EFunctorOf a b t = (EFunctor t, EDom t ~ a, ECod t ~ b)
data Id (k :: * -> * -> *) = Id
instance ECategory k => EFunctor (Id k) where
type EDom (Id k) = k
type ECod (Id k) = k
type Id k :%% a = a
Id %% a = a
map Id = hom
data (g :.: h) where
(:.:) :: (EFunctor g, EFunctor h, ECod h ~ EDom g) => g -> h -> g :.: h
instance (ECategory (ECod g), ECategory (EDom h), V (EDom h) ~ V (ECod g), ECod h ~ EDom g) => EFunctor (g :.: h) where
type EDom (g :.: h) = EDom h
type ECod (g :.: h) = ECod g
type (g :.: h) :%% a = g :%% (h :%% a)
(g :.: h) %% a = g %% (h %% a)
map (g :.: h) a b = map g (h %% a) (h %% b) . map h a b
data Const (c1 :: * -> * -> *) (c2 :: * -> * -> *) x where
Const :: Obj c2 x -> Const c1 c2 x
instance (ECategory c1, ECategory c2, V c1 ~ V c2) => EFunctor (Const c1 c2 x) where
type EDom (Const c1 c2 x) = c1
type ECod (Const c1 c2 x) = c2
type Const c1 c2 x :%% a = x
Const x %% _ = x
map (Const x) a b = id x . terminate (hom a b)
data Opposite f where
Opposite :: EFunctor f => f -> Opposite f
instance (EFunctor f) => EFunctor (Opposite f) where
type EDom (Opposite f) = EOp (EDom f)
type ECod (Opposite f) = EOp (ECod f)
type Opposite f :%% a = f :%% a
Opposite f %% EOp a = EOp (f %% a)
map (Opposite f) (EOp a) (EOp b) = map f b a
data f1 :<*>: f2 = f1 :<*>: f2
instance (EFunctor f1, EFunctor f2, V (ECod f1) ~ V (ECod f2)) => EFunctor (f1 :<*>: f2) where
type EDom (f1 :<*>: f2) = EDom f1 :<>: EDom f2
type ECod (f1 :<*>: f2) = ECod f1 :<>: ECod f2
type (f1 :<*>: f2) :%% (a1, a2) = (f1 :%% a1, f2 :%% a2)
(f1 :<*>: f2) %% (a1 :<>: a2) = (f1 %% a1) :<>: (f2 %% a2)
map (f1 :<*>: f2) (a1 :<>: a2) (b1 :<>: b2) = map f1 a1 b1 *** map f2 a2 b2
data DiagProd (k :: * -> * -> *) = DiagProd
instance ECategory k => EFunctor (DiagProd k) where
type EDom (DiagProd k) = k
type ECod (DiagProd k) = k :<>: k
type DiagProd k :%% a = (a, a)
DiagProd %% a = a :<>: a
map DiagProd a b = hom a b &&& hom a b
newtype UnderlyingF f = UnderlyingF f
instance EFunctor f => Functor (UnderlyingF f) where
type Dom (UnderlyingF f) = Underlying (EDom f)
type Cod (UnderlyingF f) = Underlying (ECod f)
type UnderlyingF f :% a = f :%% a
UnderlyingF f % Underlying a ab b = Underlying (f %% a) (map f a b . ab) (f %% b)
data EHom (k :: * -> * -> *) = EHom
instance ECategory k => EFunctor (EHom k) where
type EDom (EHom k) = EOp k :<>: k
type ECod (EHom k) = Self (V k)
type EHom k :%% (a, b) = k $ (a, b)
EHom %% (EOp a :<>: b) = Self (hom a b)
map EHom (EOp a1 :<>: a2) (EOp b1 :<>: b2) = curry (ba *** ab) a b (comp b1 a1 b2 . (comp a1 a2 b2 . (proj2 ba ab *** a) &&& proj1 ba ab . proj1 (ba *** ab) a))
where
a = hom a1 a2
b = hom b1 b2
ba = hom b1 a1
ab = hom a2 b2
data ENat :: (* -> * -> *) -> (* -> * -> *) -> * -> * -> * where
ENat :: (EFunctorOf c d f, EFunctorOf c d g)
=> f -> g -> (forall z. Obj c z -> Arr d (f :%% z) (g :%% z)) -> ENat c d f g
data EHomX_ k x = EHomX_ (Obj k x)
instance ECategory k => EFunctor (EHomX_ k x) where
type EDom (EHomX_ k x) = k
type ECod (EHomX_ k x) = Self (V k)
type EHomX_ k x :%% y = k $ (x, y)
EHomX_ x %% y = Self (hom x y)
map (EHomX_ x) a b = curry (hom a b) (hom x a) (hom x b) (comp x a b)
data EHom_X k x = EHom_X (Obj (EOp k) x)
instance ECategory k => EFunctor (EHom_X k x) where
type EDom (EHom_X k x) = EOp k
type ECod (EHom_X k x) = Self (V k)
type EHom_X k x :%% y = k $ (y, x)
EHom_X x %% y = Self (hom x y)
map (EHom_X x) a b = curry (hom a b) (hom x a) (hom x b) (comp x a b)
type VProfunctor k l t = EFunctorOf (EOp k :<>: l) (Self (V k)) t
type family End (v :: * -> * -> *) t :: *
class CartesianClosed v => HasEnds v where
end :: (VProfunctor k k t, V k ~ v) => t -> Obj v (End v t)
endCounit :: (VProfunctor k k t, V k ~ v) => t -> Obj k a -> v (End v t) (t :%% (a, a))
endFactorizer :: (VProfunctor k k t, V k ~ v) => t -> (forall a. Obj k a -> v x (t :%% (a, a))) -> v x (End v t)
newtype HaskEnd t = HaskEnd { getHaskEnd :: forall k a. VProfunctor k k t => t -> Obj k a -> t :%% (a, a) }
type instance End (->) t = HaskEnd t
instance HasEnds (->) where
end _ e = e
endCounit t a (HaskEnd e) = e t a
endFactorizer _ e x = HaskEnd (\_ a -> e a x)
data FunCat a b t s where
FArr :: (EFunctorOf a b t, EFunctorOf a b s) => t -> s -> FunCat a b t s
type t :->>: s = EHom (ECod t) :.: (Opposite t :<*>: s)
(->>) :: (EFunctor t, EFunctor s, ECod t ~ ECod s, V (ECod t) ~ V (ECod s)) => t -> s -> t :->>: s
t ->> s = EHom :.: (Opposite t :<*>: s)
instance (HasEnds (V a), V a ~ V b) => ECategory (FunCat a b) where
type V (FunCat a b) = V a
type FunCat a b $ (t, s) = End (V a) (t :->>: s)
hom (FArr t _) (FArr s _) = end (t ->> s)
id (FArr t _) = endFactorizer (t ->> t) (\a -> id (t %% a))
comp (FArr t _) (FArr s _) (FArr r _) = endFactorizer (t ->> r)
(\a -> comp (t %% a) (s %% a) (r %% a) . (endCounit (s ->> r) a *** endCounit (t ->> s) a))
data EndFunctor (k :: * -> * -> *) = EndFunctor
instance (HasEnds (V k), ECategory k) => EFunctor (EndFunctor k) where
type EDom (EndFunctor k) = FunCat (EOp k :<>: k) (Self (V k))
type ECod (EndFunctor k) = Self (V k)
type EndFunctor k :%% t = End (V k) t
EndFunctor %% (FArr t _) = Self (end t)
map EndFunctor (FArr f _) (FArr g _) = curry (end (f ->> g)) (end f) (end g) (endFactorizer g (\a ->
let aa = EOp a :<>: a in apply (getSelf (f %% aa)) (getSelf (g %% aa)) . (endCounit (f ->> g) aa *** endCounit f a)))
type family WeigtedLimit (k :: * -> * -> *) w d :: *
type Lim w d = WeigtedLimit (ECod d) w d
class HasEnds (V k) => HasLimits k where
limitObj :: (EFunctorOf j k d, EFunctorOf j (Self (V k)) w) => w -> d -> Obj k (Lim w d)
limit :: (EFunctorOf j k d, EFunctorOf j (Self (V k)) w) => w -> d -> Obj k e -> V k (End (V k) (w :->>: (EHomX_ k e :.: d))) (k $ (e, Lim w d))
limitInv :: (EFunctorOf j k d, EFunctorOf j (Self (V k)) w) => w -> d -> Obj k e -> V k (k $ (e, Lim w d)) (End (V k) (w :->>: (EHomX_ k e :.: d)))
type family WeigtedColimit (k :: * -> * -> *) w d :: *
type Colim w d = WeigtedColimit (ECod d) w d
class HasEnds (V k) => HasColimits k where
colimitObj :: (EFunctorOf j k d, EFunctorOf (EOp j) (Self (V k)) w) => w -> d -> Obj k (Colim w d)
colimit :: (EFunctorOf j k d, EFunctorOf (EOp j) (Self (V k)) w) => w -> d -> Obj k e -> V k (End (V k) (w :->>: (EHom_X k e :.: Opposite d))) (k $ (Colim w d, e))
colimitInv :: (EFunctorOf j k d, EFunctorOf (EOp j) (Self (V k)) w) => w -> d -> Obj k e -> V k (k $ (Colim w d, e)) (End (V k) (w :->>: (EHom_X k e :.: Opposite d)))
type instance WeigtedLimit (Self v) w d = End v (w :->>: d)
instance HasEnds v => HasLimits (Self v) where
limitObj w d = Self (end (w ->> d))
limit w d (Self e) = let wed = w ->> (EHomX_ (Self e) :.: d) in curry (end wed) e (end (w ->> d))
(endFactorizer (w ->> d) (\a -> let { Self wa = w %% a; Self da = d %% a } in apply e (da ^^^ wa) . (flip wa e da . endCounit wed a *** e)))
limitInv w d (Self e) = let wed = w ->> (EHomX_ (Self e) :.: d) in endFactorizer wed
(\a -> let { Self wa = w %% a; Self da = d %% a } in flip e wa da . (endCounit (w ->> d) a ^^^ e))
yoneda :: forall f k x. (HasEnds (V k), EFunctorOf k (Self (V k)) f) => f -> Obj k x -> V k (End (V k) (EHomX_ k x :->>: f)) (f :%% x)
yoneda f x = apply (hom x x) (getSelf (f %% x)) . (endCounit (EHomX_ x ->> f) x &&& id x . terminate (end (EHomX_ x ->> f)))
yonedaInv :: forall f k x. (HasEnds (V k), EFunctorOf k (Self (V k)) f) => f -> Obj k x -> V k (f :%% x) (End (V k) (EHomX_ k x :->>: f))
yonedaInv f x = endFactorizer (EHomX_ x ->> f) h
where
h :: Obj k a -> V k (f :%% x) (Exponential (V k) (k $ (x, a)) (f :%% a))
h a = curry fx xa fa (apply fx fa . (map f x a . proj2 fx xa &&& proj1 fx xa))
where
xa = hom x a
Self fx = f %% x
Self fa = f %% a
data Y (k :: * -> * -> *) = Y
instance (ECategory k, HasEnds (V k)) => EFunctor (Y k) where
type EDom (Y k) = EOp k
type ECod (Y k) = FunCat k (Self (V k))
type Y k :%% x = EHomX_ k x
Y %% EOp x = FArr (EHomX_ x) (EHomX_ x)
map Y (EOp a) (EOp b) = yonedaInv (EHomX_ b) a
data One
data Two
data Three
data PosetTest a b where
One :: PosetTest One One
Two :: PosetTest Two Two
Three :: PosetTest Three Three
type family Poset3 a b where
Poset3 Two One = Fls
Poset3 Three One = Fls
Poset3 Three Two = Fls
Poset3 a b = Tru
instance ECategory PosetTest where
type V PosetTest = Boolean
type PosetTest $ (a, b) = Poset3 a b
hom One One = Tru
hom One Two = Tru
hom One Three = Tru
hom Two One = Fls
hom Two Two = Tru
hom Two Three = Tru
hom Three One = Fls
hom Three Two = Fls
hom Three Three = Tru
id One = Tru
id Two = Tru
id Three = Tru
comp One One One = Tru
comp One One Two = Tru
comp One One Three = Tru
comp One Two One = F2T
comp One Two Two = Tru
comp One Two Three = Tru
comp One Three One = F2T
comp One Three Two = F2T
comp One Three Three = Tru
comp Two One One = Fls
comp Two One Two = F2T
comp Two One Three = F2T
comp Two Two One = Fls
comp Two Two Two = Tru
comp Two Two Three = Tru
comp Two Three One = Fls
comp Two Three Two = F2T
comp Two Three Three = Tru
comp Three One One = Fls
comp Three One Two = Fls
comp Three One Three = F2T
comp Three Two One = Fls
comp Three Two Two = Fls
comp Three Two Three = F2T
comp Three Three One = Fls
comp Three Three Two = Fls
comp Three Three Three = Tru