module Cat.Functor.Profunctor where

ProfunctorsπŸ”—

A profunctor is a bifunctor 1 As with presheaves, we define Profunctor parametrically over the universe level in which the functors are valued. Much like a presheaf on can be thought of as a predicate on a profunctor can be thought of as a relation between and

Profunctor : (C : Precategory o β„“) (D : Precategory o' β„“') (ΞΊ : Level) β†’ Type _
Profunctor C D β„“ = Bifunctor (D ^op) C (Sets β„“)

In the formalisation, we use _↬_ to indicate that both categories are small relative to some universe and that the profunctors will be valued in this universe. This restricted situation allows defining a bicategory of precategories, profunctors, and natural transformations.

_↬_ : Precategory β„“ β„“ β†’ Precategory β„“ β„“ β†’ Precategory _ _
_↬_ {β„“ = β„“} C D = Cat[ D ^op , Cat[ C , Sets β„“ ] ]

module Prof {β„“} {C D : Precategory β„“ β„“} = Cat.Reasoning (C ↬ D)

Profunctor compositionπŸ”—

The composition of profunctors and computes, at each pair the set of ways in which an object can β€œbridge the gap” between and We start by considering the type whose inhabitants are triples This can be made functorial in and using the functorial actions of on and on respectively; this construction is even functorial in and so it has the right type to be the composition However, it is not: none of the bicategorical coherences are constructible.

Suppose we have and we want to show that composition is unital on the left, i.e. we want to construct a (natural) isomorphism In one direction, we can send to the triple In the other, where we have a triple the functorial action of on its left variable is a function Tracing an element through this process computes as we wanted; In the converse direction, tracing a triple results instead in but we have no hope of showing to even compare the rest of the pairs. However, if we recall that we can rewrite our original triple as instead making it clear that we started with a triple constructed by applying the right action of on the left coordinate, but ended up with one where the right coordinate is under the left action of Generically, then, we want to identify all triples which differ only by this swap of which action is used for the variable. This is a canned categorical construction: the coend

We start by constructing the diagram over which the coend will be taken. Note that this uses the right action of and the left action of

  procompose-diagram : ⌞ C ⌟ β†’ ⌞ E ⌟ β†’ ⌞ D ↬ D ⌟
  procompose-diagram c e = make-bifunctor Ξ» where
    .Fβ‚€ d⁻ d⁺ .∣_∣   β†’ ⌞ F Β· e Β· d⁺ ⌟ Γ— ⌞ G Β· d⁻ Β· c ⌟
    .lmap f (a , b) β†’ a , G.lmap f b
    .rmap f (a , b) β†’ F.rmap f a , b

We can then calculate that, even after imposing the extranaturality condition, we can still extend the actions of and on the extremities into actions on the coend. This uses the left action of and the right action of

  procompose : Profunctor C E _
  procompose = make-bifunctor mk where
    mk : Make-bifunctor {C = E ^op} {C} {Sets _}
    mk .Fβ‚€ e c = procompose-coend.nadir c e
    mk .lmap {a} {b} {x} f = rec! Ξ» where
      .inc* c a b β†’ begin c (F.lmap f a , b)
      .glue*      β†’ ext Ξ» x y g Ξ± Ξ² β†’
        begin _ (F.lmap f (F.rmap g Ξ±) , Ξ²) β‰‘βŸ¨ ap (begin _) (F.lrmap _ _ Β·β‚š _ ,β‚š refl) βŸ©β‰‘
        begin _ (F.rmap g (F.lmap f Ξ±) , Ξ²) β‰‘βŸ¨ coend-glue _ _ βŸ©β‰‘
        begin _ (F.lmap f α , G.lmap g β)   ∎
The rest of the calculation is symmetric.
    mk .rmap {a} {b} {x} f = rec! Ξ» where
      .inc* c a b β†’ begin c (a , G.rmap f b)
      .glue*      β†’ ext Ξ» x y g Ξ± Ξ² β†’
        begin _ (F.rmap g Ξ± , G.rmap f Ξ²)   β‰‘βŸ¨ coend-glue _ _ βŸ©β‰‘
        begin _ (Ξ± , G.lmap g (G.rmap f Ξ²)) β‰‘βŸ¨ ap (begin _) (refl ,β‚š G.lrmap _ _ Β·β‚š _)  βŸ©β‰‘
        begin _ (α , G.rmap f (G.lmap g β)) ∎

    mk .lmap-id    = ext Ξ» a b c β†’ ap (begin _) (Fβ—€.elim   refl Β·β‚š _ ,β‚š refl)
    mk .lmap-∘ f g = ext Ξ» a b c β†’ ap (begin _) (Fβ—€.expand refl Β·β‚š _ ,β‚š refl)
    mk .rmap-id    = ext Ξ» a b c β†’ ap (begin _) (refl ,β‚š Gβ–Ά.elim   refl Β·β‚š _)
    mk .rmap-∘ f g = ext Ξ» a b c β†’ ap (begin _) (refl ,β‚š Gβ–Ά.expand refl Β·β‚š _)
    mk .lrmap  f g = ext Ξ» a b c β†’ refl
It is also straightforward to show that procompose can be made into a bifunctor between profunctor categories.
procompose-functor : Bifunctor (D ↬ E) (C ↬ D) (C ↬ E)
procompose-functor = make-bifunctor mk where
  mk : Make-bifunctor
  mk .Fβ‚€   = procompose
  mk .lmap {F} {G} {H} f .Ξ· x .Ξ· y = rec! Ξ» where
    .inc* c a b β†’ begin c (f Β· x Β· c Β· a , b)
    .glue*      β†’ ext Ξ» x y h a b β†’
      begin x (f Β· _ Β· x Β· Bifunctor.rmap F h a , b)   β‰‘βŸ¨ ap (begin _) (Binatural.natural-β–Ά f Β·β‚š _ ,β‚š refl) βŸ©β‰‘
      begin x (Bifunctor.rmap G h (f Β· _ Β· y Β· a) , b) β‰‘βŸ¨ coend-glue _ _ βŸ©β‰‘
      begin y (f · _ · y · a , Bifunctor.lmap H h b)   ∎
  mk .rmap {F} {G} {H} f .Ξ· x .Ξ· y = rec! Ξ» where
    .inc* c a b β†’ begin c (a , f Β· c Β· y Β· b)
    .glue*      β†’ ext Ξ» x y h a b β†’
      begin x (Bifunctor.rmap H h a , f Β· x Β· _ Β· b)   β‰‘βŸ¨ coend-glue _ _ βŸ©β‰‘
      begin y (a , Bifunctor.lmap G h (f Β· x Β· _ Β· b)) β‰‘βŸ¨ ap (begin _) (refl ,β‚š sym (Binatural.natural-β—€ f Β·β‚š _)) βŸ©β‰‘
      begin y (a , f · y · _ · Bifunctor.lmap F h b)   ∎

  mk .lmap f .Ξ· G .is-natural x y g = ext Ξ» a b c β†’ refl
  mk .lmap {F} {G} {H} f .is-natural x y g = ext Ξ» a b c d β†’
    ap (begin _) (Binatural.natural-β—€ f Β·β‚š _ ,β‚š refl)

  mk .rmap {F} {G} {H} f .Ξ· x .is-natural _ _ _ = ext Ξ» a b c β†’
    ap (begin _) (refl ,β‚š Binatural.natural-β–Ά f Β·β‚š _)
  mk .rmap {F} {G} {H} f .is-natural x y f₁ = ext Ξ» a b c d β†’ refl

  mk .lmap-id    = ext Ξ» i j k x y β†’ refl
  mk .rmap-id    = ext Ξ» i j k x y β†’ refl
  mk .lmap-∘ f g = ext Ξ» i j k x y β†’ refl
  mk .rmap-∘ f g = ext Ξ» i j k x y β†’ refl
  mk .lrmap  f g = ext Ξ» i j k x y β†’ refl

Since it was used to motivate the coend, we linger on the definition of the left unit coherence. The maps are as described above: if we start with a triple (the eta case), we use the left action of to put everything together. In the inv case, we form a triple by grouping an element with the identity map.

procompose-idl : (G : ⌞ C ↬ D ⌟) β†’ procompose (Hom[-,-] D) G Prof.β‰… G
procompose-idl {D = D} G = to-natural-iso mk where
  module G = Bifunctor G
  module D = Precategory D

  mk : make-natural-iso _ _
  mk .eta a .Ξ· b = rec! Ξ» where
    .inc* y h g β†’ G.lmap h g
    .glue*      β†’ ext Ξ» x y f z g β†’ Fr.expand (G.Left _) refl Β·β‚š _
  mk .inv a .Ξ· b g = begin a (D.id , g)

To show that these cancel, we first use the extranaturality we imposed to swap the actions along the coordinates, then remove the extra composite from the action of

  mk .inv∘eta a = ext Ξ» b y h g β†’
    begin a (D.id , G.lmap h g) β‰‘Λ˜βŸ¨ coend-glue _ _ βŸ©β‰‘Λ˜
    begin y (h D.∘ D.id , g)    β‰‘βŸ¨ ap (begin _) (D.idr _ ,β‚š refl) βŸ©β‰‘
    begin y (h , g)             ∎
The rest of the coherence data is analogous.
procompose-idr : (F : ⌞ C ↬ D ⌟) β†’ procompose F (Hom[-,-] C) Prof.β‰… F
procompose-idr {C = C} F = to-natural-iso mk where
  module F = Bifunctor F
  module C = Precategory C

  mk : make-natural-iso _ _
  mk .eta x .Ξ· y = rec! Ξ» where
    .inc* _ a b β†’ F.rmap b a
    .glue*      β†’ ext Ξ» x y f z g β†’ Fr.collapse (F.Right _) refl Β·β‚š _
  mk .eta x .is-natural y z f = ext Ξ» x y z β†’ Fr.expand (F.Right _) refl Β·β‚š _
  mk .inv x .Ξ· y z = begin y (z , C.id)
  mk .inv x .is-natural y z f = ext Ξ» a β†’ coend-glue _ _ βˆ™ ap (begin _) (refl ,β‚š C.idl _ βˆ™ sym (C.idr _))
  mk .eta∘inv x     = ext Ξ» i a     β†’ F.rmap-id Β·β‚š _
  mk .inv∘eta x     = ext Ξ» i a b c β†’ coend-glue _ _ βˆ™ ap (begin _) (refl ,β‚š C.idl _)
  mk .natural x y f = ext Ξ» i a b c β†’ F.lrmap _ _ Β·β‚š _

procompose-assoc : βˆ€ {β„“} β†’ Associator-for (_↬_ {β„“ = β„“}) procompose-functor
procompose-assoc = to-natural-iso mk where
  mk : make-natural-iso _ _
  mk .eta (F , G , H) .Ξ· y .Ξ· i = rec! Ξ» where
    .inc* _ .inc* _ a b c β†’ begin _ (a , begin _ (b , c))
    .inc* _ .glue* β†’ ext Ξ» i j h x y z β†’ coend-glue _ _
    .glue* β†’ ext Ξ» i j h k x y z β†’ ap (begin _) (refl ,β‚š coend-glue _ _)

  mk .inv (F , G , H) .Ξ· x .Ξ· y = rec! Ξ» where
    .inc* _ a .inc* _ b c β†’ begin _ (begin _ (a , b) , c)
    .inc* _ a .glue* β†’ ext Ξ» j h x y z β†’ coend-glue _ _
    .glue* β†’ ext Ξ» i j h k x y z β†’ ap (begin _) (coend-glue _ _ ,β‚š refl)

  mk .eta x .Ξ· y .is-natural w z f = ext Ξ» a b c d e β†’ refl
  mk .eta x .is-natural y z f = ext Ξ» a b c d e h β†’ refl
  mk .inv (F , G , H) .Ξ· x .is-natural y z f = ext Ξ» a b c d e β†’ refl
  mk .inv (F , G , H) .is-natural x y f = ext Ξ» i a b c d e β†’ refl
  mk .eta∘inv (F , G , H) = ext Ξ» a b c d e f g β†’ refl
  mk .inv∘eta (F , G , H) = ext Ξ» a b c d e f g β†’ refl
  mk .natural _ _ _       = ext Ξ» a b c d e f g β†’ refl

open Prebicategory

Prof : βˆ€ β„“ β†’ Prebicategory (lsuc β„“) (lsuc β„“) β„“
Prof β„“ .Ob      = Precategory β„“ β„“
Prof β„“ .Hom     = _↬_
Prof β„“ .id      = Hom[-,-] _
Prof β„“ .compose = procompose-functor
Prof β„“ .unitor-r = to-natural-iso mk where
  mk : make-natural-iso _ _
  mk .eta F   = Prof.from (procompose-idr F)
  mk .inv F   = Prof.to (procompose-idr F)
  mk .eta∘inv F = Prof.invr (procompose-idr F)
  mk .inv∘eta F = Prof.invl (procompose-idr F)
  mk .natural F G h = ext Ξ» i j x β†’ refl
Prof β„“ .unitor-l = to-natural-iso mk where
  mk : make-natural-iso _ _
  mk .eta F   = Prof.from (procompose-idl F)
  mk .inv F   = Prof.to (procompose-idl F)
  mk .eta∘inv F = Prof.invr (procompose-idl F)
  mk .inv∘eta F = Prof.invl (procompose-idl F)
  mk .natural F G h = ext Ξ» i j x β†’ refl
Prof β„“ .associator = procompose-assoc
Prof β„“ .triangle f g      = ext Ξ» i j x a y h b     β†’ coend-glue _ _
Prof β„“ .pentagon f g h i  = ext Ξ» i j k x l y m z h β†’ refl

  1. We write with the contravariant variable on the right, to indicate that is equipped with a right action of

    This convention is also informed by wanting that functors to induce profunctors β†©οΈŽ