Adjunctions
Tutorial Video
Text description (accessibility)
This video demonstrates the "Adjunctions" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. An adjunction between two functors `F` and `G` is a natural bijection between morphisms: `Hom(F A, B) ≅ Hom(A, G B)`. Key difference from OCaml: | Aspect | Rust | OCaml |
Tutorial
The Problem
An adjunction between two functors F and G is a natural bijection between morphisms: Hom(F A, B) ≅ Hom(A, G B). Adjunctions are the categorical generalization of "best approximations" and appear everywhere in functional programming: currying is an adjunction, the product/exponent adjunction underlies closures, and many monad/comonad pairs arise from adjunctions. This example implements adjunctions in Rust and shows how the State and Env comonad/monad pair emerges from the product adjunction.
🎯 Learning Outcomes
unit and counit natural transformationsG ∘ F using adjunction dataF ∘ G using adjunction dataCode Example
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Key Differences
| Aspect | Rust | OCaml |
|---|---|---|
| Functor encoding | trait + struct | module type + module |
| Type families | associated types | module type parameters |
| Adjunction laws | runtime tests | module coherence |
| Higher-kinded | simulated via GATs | module polymorphism |
| Monad derivation | manual bind | can derive via functor composition |
Adjunctions provide a systematic way to derive monads and comonads: every adjunction gives rise to a monad G ∘ F and a comonad F ∘ G.
OCaml Approach
OCaml uses functors (module-level) for adjunctions:
module type ADJUNCTION = sig
type 'a left_f (* F A *)
type 'a right_g (* G B *)
val unit : 'a -> 'a left_f right_g
val counit : 'a right_g left_f -> 'a
end
(* Product adjunction: F = (E *), G = (E ->) *)
module ProdAdj (E : sig type t val e : t end) = struct
type 'a left_f = E.t * 'a
type 'a right_g = E.t -> 'a
let unit a e = (e, a)
let counit (e, f) = f e
end
OCaml functors map cleanly to categorical functors; Rust traits simulate the same with more verbosity.
Full Source
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Deep Comparison
OCaml vs Rust: Adjunctions
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
Δ ⊣ × (diagonal functor left adjoint to product), which gives rise to the tuple monad.G(ε) ∘ η_G = id_G and ε_F ∘ F(η) = id_F.Writer<W, A> monad from the adjunction between (- × W) and (W →) where W is a monoid.List monad arises from the free/forgetful adjunction between Set and Mon (monoids).f: F A -> B, produce f̂: A -> G B using unit and fmap.