module Cat.Diagram.Monad.Kleisli where
Kleisli maps🔗
Let be a monad. A Kleisli map from to with respect to is a morphism Like any reasonable notion of map, Kleisli maps can be organized into a category.
: Precategory o ℓ
Kleisli-maps .Precategory.Ob = Ob
Kleisli-maps .Precategory.Hom X Y = Hom X (M₀ Y)
Kleisli-maps .Precategory.Hom-set _ _ = Hom-set _ _ Kleisli-maps
The identity Kleisli map is simply the unit of the monad, and composition of Kleisli maps is given by the following formula:
.Precategory.id = η _
Kleisli-maps .Precategory._∘_ f g = μ _ ∘ M₁ f ∘ g Kleisli-maps
The category equations all follow from simple yet tedious algebra. Luckily, the algebra is simple enough that we can automate it away!
.Precategory.idr _ =
Kleisli-maps (sym (unit.is-natural _ _ _)) right-ident
lswizzle .Precategory.idl _ =
Kleisli-maps
cancell left-ident.Precategory.assoc _ _ _ = monad! M Kleisli-maps
Note that each Kleisli map can be extended to an homomorphism between free -algebras on and via This allows us to construct a functor from the category of Kleisli maps into the Kleisli category of
: Functor Kleisli-maps (Kleisli M)
Kleisli-maps→Kleisli .Functor.F₀ X = Free.₀ X , inc (X , EM.id-iso)
Kleisli-maps→Kleisli .Functor.F₁ f .hom = μ _ ∘ M₁ f
Kleisli-maps→Kleisli .Functor.F₁ f .preserves = monad! M Kleisli-maps→Kleisli
We opt to omit the functoriality proofs, as they are not particularly interesting.
.Functor.F-id =
Kleisli-maps→Kleisli
ext left-ident.Functor.F-∘ f g =
Kleisli-maps→Kleisli (MR.shufflel mult-assoc ∙ pushr (MR.shufflel (mult.is-natural _ _ _))) ext
A bit of quick algebra shows us that this functor is faithful.
: is-faithful Kleisli-maps→Kleisli
Kleisli-maps→Kleisli-is-faithful {_} {_} {f} {g} p =
Kleisli-maps→Kleisli-is-faithful
f ≡⟨ monad! M ⟩(μ _ ∘ M₁ f) ∘ η _ ≡⟨ ap₂ _∘_ (ap hom p) refl ⟩
(μ _ ∘ M₁ g) ∘ η _ ≡⟨ monad! M ⟩
g ∎
Moreover, this functor is full, as every homomorphism between free can be transformed into a Kleisli map by precomposing with the unit of the monad.
: is-full Kleisli-maps→Kleisli
Kleisli-maps→Kleisli-is-full {X} {Y} f =
Kleisli-maps→Kleisli-is-full ((f .hom ∘ η _) , ext lemma)
pure where
: μ Y ∘ M₁ (f .hom ∘ η X) ≡ f .hom
lemma =
lemma _ ∘ M₁ (f .hom ∘ η _) ≡⟨ MR.popl (sym (f .preserves)) ⟩
μ (f .hom ∘ μ _) ∘ M₁ (η _) ≡⟨ cancelr left-ident ⟩
.hom ∎ f
Finally, this functor is essentially surjective. In other words, the category of Kleisli maps is weakly equivalent to the Kleisli category!
: is-eso Kleisli-maps→Kleisli
Kleisli-maps→Kleisli-is-eso ((X , alg) , essentially-free) = do
Kleisli-maps→Kleisli-is-eso
A , free ← essentially-free(A , (super-iso→sub-iso _ free)) pure
Note that we cannot upgrade this weak equivalence to an equivalence when is univalent, as categories of Kleisli maps are not, in general, univalent. To see why, consider the monad on that maps every set to Note that every hom set of the corresponding category of Kleisli maps is contractible, as all maps are of the form This in turn means that the type of isos is contractible; if the Kleisli map category were univalent, then this would imply that the type of sets was a proposition.
Kleisli-not-univalent: ∀ {κ}
→ Σ[ C ∈ Precategory (lsuc κ) κ ]
Σ[ M ∈ Monad C ](is-category C × (¬ is-category (Kleisli-maps M)))
{κ} =
Kleisli-not-univalent
Sets κ , T , Sets-is-category , not-univalentwhere
: Monad (Sets κ)
T =
T
Adjunction→Monad $(Sets κ)
is-terminal→inclusion-is-right-adjoint (el! (Lift _ ⊤))
(λ _ → hlevel 0)
open Cat.Reasoning (Kleisli-maps T)
: ¬ is-category (Kleisli-maps T)
not-univalent =
not-univalent cat
¬Set-is-prop $0 cat $ λ X Y →
identity-system→hlevel (hlevel 0) ≅-is-contr
Properties🔗
module _ {o ℓ} {C : Precategory o ℓ} {M : Monad C} where
private
module M = Monad M
module MR = Cat.Functor.Reasoning M.M
module EM = Cat.Reasoning (Eilenberg-Moore M)
module Free = Functor (Free-EM {M = M})
open M hiding (M)
open Cat.Reasoning C
As shown in the previous section, the category of Kleisli maps is weakly equivalent to the Kleisli category, so it inherits all of the Kleisli category’s nice properties. In particular, the forgetful functor from the category of Kleisli maps is faithful, conservative, and has a left adjoint.
: Functor (Kleisli-maps M) C
Forget-Kleisli-maps = Forget-Kleisli F∘ Kleisli-maps→Kleisli M
Forget-Kleisli-maps
: is-faithful Forget-Kleisli-maps
Forget-Kleisli-maps-is-faithful =
Forget-Kleisli-maps-is-faithful p (Forget-EM-is-faithful p)
Kleisli-maps→Kleisli-is-faithful M
: is-conservative Forget-Kleisli-maps
Forget-Kleisli-maps-is-conservative =
Forget-Kleisli-maps-is-conservative f-inv {F = Kleisli-maps→Kleisli M} (Kleisli-maps→Kleisli-is-ff M) _ $
is-ff→is-conservative _ $
super-inv→sub-inv
Forget-EM-is-conservative f-inv
: Functor C (Kleisli-maps M)
Free-Kleisli-maps .Functor.F₀ X = X
Free-Kleisli-maps .Functor.F₁ f = η _ ∘ f
Free-Kleisli-maps .Functor.F-id = idr _
Free-Kleisli-maps .Functor.F-∘ f g = monad! M
Free-Kleisli-maps
: Free-Kleisli-maps ⊣ Forget-Kleisli-maps
Free-Kleisli-maps⊣Forget-Kleisli-maps ._⊣_.unit ._=>_.η = η
Free-Kleisli-maps⊣Forget-Kleisli-maps ._⊣_.unit ._=>_.is-natural _ _ f = monad! M
Free-Kleisli-maps⊣Forget-Kleisli-maps ._⊣_.counit ._=>_.η _ = id
Free-Kleisli-maps⊣Forget-Kleisli-maps ._⊣_.counit ._=>_.is-natural _ _ f = monad! M
Free-Kleisli-maps⊣Forget-Kleisli-maps ._⊣_.zig = monad! M
Free-Kleisli-maps⊣Forget-Kleisli-maps ._⊣_.zag = monad! M Free-Kleisli-maps⊣Forget-Kleisli-maps