proarrow-0.1.0.0: src/Proarrow/Colimit.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
-- | Profunctor-weighted colimits: @'HasColimits' j k@ says @k@ has colimits of @k '+->' i@-diagrams
-- weighted by @j@, given by the 'Colimit' profunctor with 'colimit' and 'colimitUniv'. The
-- 'Proarrow.Profunctor.Instance.Terminal.TerminalProfunctor' weight gives ordinary conical
-- colimits, e.g. initial objects, binary coproducts and copowers.
--
-- As in "Proarrow.Limit", the weight synonyms and shape helpers (@Unweighted@, @O1@\/@O2@,
-- @At1@\/@At2@, @Hom@, @Lan@) are not exported, since their names clash with ones elsewhere.
module Proarrow.Colimit
( HasColimits (..)
, IsCorepColimit
, mapColimit
, CoproductColimit
, CopowerLimit
, Coend (..)
, CoendLimit
, AnyColimit (..)
) where
import Data.Function (($))
import Data.Kind (Constraint, Type)
import Proarrow.Category.Instance.Coproduct (COPRODUCT (..), IsLR (..))
import Proarrow.Category.Instance.Opposite (OPPOSITE (..), Op (..))
import Proarrow.Category.Instance.Product ((:**:) (..))
import Proarrow.Category.Instance.Prof (Prof (..))
import Proarrow.Category.Instance.Unit (Unit (..))
import Proarrow.Category.Instance.Zero (VOID)
import Proarrow.Colimit.BinaryCoproduct (HasBinaryCoproducts (..), lft, rgt)
import Proarrow.Colimit.Copower (Copowered (..))
import Proarrow.Colimit.Initial (HasInitialObject (..), initiate)
import Proarrow.Core (CAT, CategoryOf (..), Kind, Profunctor (..), Promonad (..), lmap, (//), (:~>), type (+->))
import Proarrow.Functor (Copresheaf, Functor (..), FunctorForRep (..), Presheaf)
import Proarrow.Profunctor.Corepresentable (Corep (..), Corepresentable (..), corepUniv, withObCorep)
import Proarrow.Profunctor.Instance.Composition ((:.:) (..))
import Proarrow.Profunctor.Instance.Constant (Constant)
import Proarrow.Profunctor.Instance.Costar (Costar, pattern Costar)
import Proarrow.Profunctor.Instance.HaskValue (HaskValue (..))
import Proarrow.Profunctor.Instance.Identity (Id (..))
import Proarrow.Profunctor.Instance.Terminal (TerminalProfunctor (..))
import Proarrow.Profunctor.Representable (Rep (..), Representable (..))
type Unweighted = TerminalProfunctor
class (Corepresentable (Colimit j d)) => IsCorepColimit j d
instance (Corepresentable (Colimit j d)) => IsCorepColimit j d
-- | profunctor-weighted colimits
type HasColimits :: forall {i} {a}. a +-> i -> Kind -> Constraint
class (Profunctor j, forall (d :: k +-> i). (Corepresentable d) => IsCorepColimit j d) => HasColimits (j :: a +-> i) k where
type Colimit (j :: a +-> i) (d :: k +-> i) :: k +-> a
colimit :: (Corepresentable (d :: k +-> i)) => j :.: Colimit j d :~> d
colimitUniv :: (Corepresentable (d :: k +-> i), Profunctor p) => (j :.: p :~> d) -> p :~> Colimit j d
mapColimit
:: forall {i} j k p q
. (HasColimits j k, Corepresentable p, Corepresentable q) => (p :: k +-> i) ~> q -> Colimit j p ~> Colimit j q
mapColimit (Prof n) = Prof (colimitUniv @j (n . colimit @j))
instance (HasInitialObject k) => HasColimits (Unweighted :: Presheaf VOID) k where
type Colimit Unweighted d = Corep (Constant InitialObject)
colimit (t :.: _) = case t of {}
colimitUniv _ p = p // Corep initiate
type O1 = L '()
type O2 = R '()
type At1 d = d %% O1
type At2 d = d %% O2
data family CoproductColimit :: k +-> COPRODUCT () () -> Presheaf k
instance (HasBinaryCoproducts k, Corepresentable d) => FunctorForRep (CoproductColimit d :: Presheaf k) where
type CoproductColimit d @ '() = At1 d || At2 d
fmap Unit = withObCorep @d @O1 $ withObCorep @d @O2 $ withObCoprod @_ @(At1 d) @(At2 d) id
instance (HasBinaryCoproducts k) => HasColimits (Unweighted :: Presheaf (COPRODUCT () ())) k where
type Colimit Unweighted d = Corep (CoproductColimit d)
colimit @d (TerminalProfunctor @o :.: Corep f) =
withObCorep @d @O1 $
withObCorep @d @O2 $
lrCase @o
(cotabulate (f . lft @_ @(At1 d) @(At2 d)))
(cotabulate (f . rgt @_ @(At1 d) @(At2 d)))
colimitUniv n p =
p //
let l = n (TerminalProfunctor @O1 :.: p)
r = n (TerminalProfunctor @O2 :.: p)
in Corep $ coindex l ||| coindex r
data family CopowerLimit :: Type -> Copresheaf k -> Presheaf k
instance (Corepresentable d, Copowered Type k) => FunctorForRep (CopowerLimit n d :: Presheaf k) where
type CopowerLimit n d @ '() = n *. (d %% '())
fmap Unit = withObCorep @d @'() $ withObCopower @Type @k @(d %% '()) @n id
instance (Copowered Type k) => HasColimits (HaskValue n :: Presheaf ()) k where
type Colimit (HaskValue n) d = Corep (CopowerLimit n d)
colimit @d (HaskValue n :.: Corep f) = withObCorep @d @'() $ cotabulate $ uncopower f n
colimitUniv @d m p = withObCorep @d @'() $ Corep (copower \n -> coindex (m (HaskValue n :.: p))) \\ p
data Coend d where
Coend :: a ~> b -> d %% '(OP b, a) -> Coend d
data family CoendLimit :: Type +-> (OPPOSITE k, k) -> Presheaf Type
instance (Corepresentable d) => FunctorForRep (CoendLimit (d :: Type +-> (OPPOSITE k, k))) where
type CoendLimit d @ '() = Coend d
fmap Unit = id
type Hom :: Presheaf (OPPOSITE k, k)
data Hom a b where
Hom :: a ~> b -> Hom '(OP b, a) '()
instance (CategoryOf k) => Profunctor (Hom :: Presheaf (OPPOSITE k, k)) where
dimap (Op l :**: r) Unit (Hom f) = Hom (l . f . r) \\ l \\ r
r \\ Hom f = r \\ f
instance (CategoryOf k) => HasColimits (Hom :: Presheaf (OPPOSITE k, k)) Type where
type Colimit Hom d = Corep (CoendLimit d)
colimit (Hom f :.: Corep g) = f // cotabulate (\d -> g (Coend f d))
colimitUniv n p = p // Corep \(Coend f d) -> coindex (n (Hom f :.: p)) d
instance (CategoryOf j) => HasColimits (Id :: CAT j) k where
type Colimit Id d = d
colimit (Id f :.: d) = lmap f d
colimitUniv n p = n (Id id :.: p) \\ p
instance (Corepresentable j2, HasColimits j1 k, HasColimits j2 k) => HasColimits (j1 :.: j2) k where
type Colimit (j1 :.: j2) d = Colimit j2 (Colimit j1 d)
colimit @d ((j1 :.: j2) :.: c) = colimit @j1 @k @d (j1 :.: colimit @j2 @k @(Colimit j1 d) (j2 :.: c))
colimitUniv @d n = colimitUniv @j2 @k @(Colimit j1 d) (colimitUniv @j1 @k @d (\(j1 :.: (j2 :.: p')) -> n ((j1 :.: j2) :.: p')))
instance (FunctorForRep f) => HasColimits (Rep f) k where
type Colimit (Rep f) d = Corep f :.: d
colimit (Rep f :.: (Corep g :.: d)) = lmap (g . f) d
colimitUniv n p = p // corepUniv :.: n (repUniv :.: p)
newtype AnyColimit j a b = AnyColimit (j a b)
deriving newtype (Profunctor)
type Lan :: (a +-> i) -> (Type +-> i) -> a -> Type
data Lan j d a where
Lan :: j b a -> d %% b -> Lan j d a
instance (Profunctor j, Corepresentable d) => Functor (Lan j d) where
map f (Lan j d) = Lan (rmap f j) d
instance (Profunctor j) => HasColimits (AnyColimit j) Type where
type Colimit (AnyColimit j) d = Costar (Lan j d)
colimit (AnyColimit j :.: Costar f) = cotabulate (\db -> f (Lan j db)) \\ j
colimitUniv n p = p // Costar (\(Lan j db) -> coindex (n (AnyColimit j :.: p)) db)