Choice Profunctor
Tutorial Video
Text description (accessibility)
This video demonstrates the "Choice Profunctor" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. While `Strong` profunctors correspond to lenses (product types, always present), `Choice` profunctors correspond to prisms (sum types, possibly absent). Key difference from OCaml: 1. **Prism encoding**: `Choice` captures prisms just as `Strong` captures lenses; the duality (products vs. sums) maps onto profunctor classes.
Tutorial
The Problem
While Strong profunctors correspond to lenses (product types, always present), Choice profunctors correspond to prisms (sum types, possibly absent). Choice adds left: P<A, B> -> P<Either<A, C>, Either<B, C>> — the ability to "pass through" the Right(C) case while operating on Left(A) -> Left(B). Functions implement Choice naturally. A Van Laarhoven prism requires Choice: type Prism s a = ∀p. Choice p => p a b -> p s t.
🎯 Learning Outcomes
Choice as the profunctor class capturing prism-like behaviorleft and right as the two Choice operationsChoice enables "operate on one branch, pass through the other"Choice to prisms: prisms are polymorphic over all Choice profunctorsCode Example
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Key Differences
Choice captures prisms just as Strong captures lenses; the duality (products vs. sums) maps onto profunctor classes.Strong and Choice — functions can thread both product and sum context; they are simultaneously lenses and prisms (isos) in the profunctor encoding.Traversal corresponds to profunctors that are both Strong and Choice with certain coherence conditions.Wander class beyond Choice; the full hierarchy is Profunctor ⊂ Strong ⊂ Wander.OCaml Approach
OCaml's Choice profunctor:
module type CHOICE = sig
include PROFUNCTOR
val left : ('a, 'b) t -> (('a, 'c) Either.t, ('b, 'c) Either.t) t
val right : ('a, 'b) t -> (('c, 'a) Either.t, ('c, 'b) Either.t) t
end
A prism type ('s, 't, 'a, 'b) prism = { run : 'p. (module CHOICE with type ('a,'b) t = 'p) -> 'p a b -> 'p s t } requires first-class module polymorphism — OCaml handles this better than Rust.
Full Source
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Deep Comparison
OCaml vs Rust: Choice 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
left for a Kleisli<Option, A, B> profunctor — threading Option context through choice.prism_via_choice(preview, review) creating a prism from the Choice profunctor encoding.right(f) = dimap(Either::swap, Either::swap)(left(f)) — right is derivable from left.