Monad from Adjunction
Tutorial Video
Text description (accessibility)
This video demonstrates the "Monad from Adjunction" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. Every adjunction `F ⊣ G` gives rise to a monad `G ∘ F` with unit `η` and multiplication `G(ε_F)`, and a comonad `F ∘ G` with counit `ε` and comultiplication `F(η_G)`. Key difference from OCaml: | Aspect | Rust | OCaml |
Tutorial
The Problem
Every adjunction F ⊣ G gives rise to a monad G ∘ F with unit η and multiplication G(ε_F), and a comonad F ∘ G with counit ε and comultiplication F(η_G). This is the deepest connection between adjunctions, monads, and comonads. The State monad arises from the product/exponential adjunction; the List monad from the free/forgetful adjunction. This example derives the State monad and its dual the Env comonad from first principles using the product adjunction.
🎯 Learning Outcomes
G ∘ F where F = (- × S) and G = (S → -)return as the adjunction unit η and join as G(ε_F)F ∘ G from the same adjunctionCode Example
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Key Differences
| Aspect | Rust | OCaml |
|---|---|---|
| Adjunction encoding | traits + structs | module signatures |
join derivation | manual Box wrapping | direct function application |
| Monad laws | require S: Clone + 'static | implicit polymorphism |
| Law verification | runtime tests | qcheck property tests |
| Generality | product adjunction only | full module parametricity |
This derivation demonstrates that State and Env are not ad-hoc constructions but arise necessarily and uniquely from the product adjunction, with no choices involved.
OCaml Approach
OCaml's module system makes the adjunction derivation structurally cleaner:
module type ADJUNCTION = sig
type s
(* F A = (A * s), G B = s -> B *)
val unit : 'a -> s -> ('a * s) (* eta *)
val counit : (s -> 'b) * s -> 'b (* epsilon *)
end
(* Derived monad: G o F A = s -> (A * s) *)
let return_ a s = (a, s)
let join mma s = let (ma, s') = mma s in ma s'
let bind ma f s = let (a, s') = ma s in f a s'
(* Derived comonad: F o G B = (s -> B) * s *)
let extract (f, s) = f s
let duplicate (f, s) = (fun s' -> (f, s'), s)
Full Source
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Deep Comparison
OCaml vs Rust: Monad From Adjunction
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
Writer<W> monad from the adjunction (- × W) ⊣ (W →) where W is a monoid; implement tell, listen, and pass.Reader<R> monad from the diagonal/product adjunction and implement ask and local.State<S, A> to Reader<S, (A, S)> (which is just the function type) and show it respects return and bind.η and counit ε of the adjunction satisfy the triangle identities computationally by writing tests that check G(ε) ∘ ηG = idG and ε_F ∘ F(η) = idF.