Kan Extensions
Tutorial Video
Text description (accessibility)
This video demonstrates the "Kan Extensions" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. Kan extensions answer the question: "given functors `F: C -> D` and `G: C -> E`, how do we best extend or lift G along F to get a functor from D to E?" The Right Kan Extension (Ran) and Left Kan Extension (Lan) are the universal solutions to this problem. Key difference from OCaml: | Aspect | Rust | OCaml |
Tutorial
The Problem
Kan extensions answer the question: "given functors F: C -> D and G: C -> E, how do we best extend or lift G along F to get a functor from D to E?" The Right Kan Extension (Ran) and Left Kan Extension (Lan) are the universal solutions to this problem. In functional programming, Ran encodes the Yoneda lemma, and Lan gives rise to coends and existential types. Both appear in the implementation of profunctor optics and indexed traversals.
🎯 Learning Outcomes
forall b. (a -> f b) -> g b (the right extension)exists b. (f b -> a, g b) (the left extension)Code Example
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Key Differences
| Aspect | Rust | OCaml |
|---|---|---|
| Universal quantification | trait objects (limited) | rank-2 via record fields |
| Existential (Lan) | Box<dyn Any> | GADT existential binding |
| Codensity monad | explicit Rc wrapping | cleaner with polymorphic functions |
| Yoneda isomorphism | manual | directly expressible |
| Kan in practice | Codensity most useful | full generality available |
OCaml Approach
OCaml's higher-rank polymorphism makes Ran more direct:
(* Right Kan extension: Ran F G A = { run : 'b. ('a -> 'f 'b) -> 'g 'b } *)
type ('f, 'g, 'a) ran = { run : 'b. ('a -> 'b) -> 'b } (* Yoneda specialization *)
let to_yoneda : 'a -> ('f, 'g, 'a) ran = fun a -> { run = fun f -> f a }
let from_yoneda : ('f, 'g, 'a) ran -> 'a = fun ran -> ran.run Fun.id
(* Left Kan extension via existential *)
type ('f, 'g, 'a) lan = Lan : ('b -> 'a) * 'b -> ('f, 'g, 'a) lan
OCaml's GADT syntax makes existential types (Lan) particularly clean; Rust needs Box<dyn Any> as a workaround.
Full Source
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Deep Comparison
OCaml vs Rust: Kan Extensions
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.
Exercises
toYoneda: F A -> Yoneda F A and fromYoneda: Yoneda F A -> F A for F = Vec and prove they are inverses.Ran Id Id A ≅ A by implementing the isomorphism (Yoneda lemma for identity functor).fromLan: Lan F G A -> G (F^{-1} A) for a concrete invertible functor F (e.g., Newtype).