Strong Profunctor
Tutorial Video
Text description (accessibility)
This video demonstrates the "Strong Profunctor" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. A `Strong` profunctor extends a profunctor with `first: P<A, B> -> P<(A, C), (B, C)>` — the ability to "pass along" extra context `C` while the profunctor operates on `A -> B`. Key difference from OCaml: 1. **Lens encoding**: `Strong` captures exactly what makes lenses work; functions are Strong, making the function profunctor the reference implementation.
Tutorial
The Problem
A Strong profunctor extends a profunctor with first: P<A, B> -> P<(A, C), (B, C)> — the ability to "pass along" extra context C while the profunctor operates on A -> B. Functions are Strong: first(f) = |(a, c)| (f(a), c). The significance: in the profunctor optics encoding, lenses are exactly Strong profunctors. A Van Laarhoven lens type Lens s a = ∀p. Strong p => p a b -> p s t works for any Strong profunctor.
🎯 Learning Outcomes
Strong as the profunctor class that captures lens-like behaviorfirst and second as the two Strong operationsStrong by threading context throughStrong to lens encoding: lenses are polymorphic over all Strong profunctorsCode Example
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Key Differences
Strong captures exactly what makes lenses work; functions are Strong, making the function profunctor the reference implementation.first vs. second**: Both are derivable from each other given swap: second p = dimap swap swap (first p) — only one needs to be primitive.Strong extends Profunctor; Choice extends Profunctor for prisms; their intersection is affine traversals.OCaml Approach
OCaml's Strong profunctor:
module type STRONG = sig
include PROFUNCTOR
val first : ('a, 'b) t -> ('a * 'c, 'b * 'c) t
val second : ('a, 'b) t -> ('c * 'a, 'c * 'b) t
end
Lenses in the profunctor encoding: type ('s, 't, 'a, 'b) lens = { run : 'p. (module STRONG with type ('a,'b) t = 'p) -> 'p a b -> 'p s t }. This requires first-class modules and rank-2 types — OCaml handles this more naturally than Rust.
Full Source
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Deep Comparison
OCaml vs Rust: Strong Profunctor
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
Strong for Parser<A, B> (from example 238) — running a parser while threading context through.lens_via_strong(get, set) that creates a lens from get/set pair using the Strong profunctor encoding.second(f) = dimap(swap, swap)(first(f)) produces the same result as a direct second implementation.