Store Comonad
Tutorial Video
Text description (accessibility)
This video demonstrates the "Store Comonad" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. The Store comonad models a mutable reference into a larger data structure: given a "getter" function and a current focus position, you can read the value at focus, move the focus elsewhere, or derive new stores by transforming the getter. Key difference from OCaml: | Aspect | Rust | OCaml |
Tutorial
The Problem
The Store comonad models a mutable reference into a larger data structure: given a "getter" function and a current focus position, you can read the value at focus, move the focus elsewhere, or derive new stores by transforming the getter. This captures the essence of how lenses work under the hood. In Rust, implementing Store reveals how comonadic structure enables elegant data-access abstractions without mutation.
🎯 Learning Outcomes
(s -> a, s) — a getter and a current indexextract, extend, and duplicate for StoreLens abstractionseek (reposition) and peek (read at arbitrary position)Code Example
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Key Differences
| Aspect | Rust | OCaml |
|---|---|---|
| Getter sharing | Rc<dyn Fn(S) -> A> | closure captured in record |
| Clone constraint | S: Clone required | structural copy for records |
| extend lifetime | 'static bounds needed | no lifetime tracking |
| Lens connection | explicit derivation | directly via records |
| Performance | zero-cost with monomorphization | GC-managed closures |
Store comonad is the semantic foundation of the van Laarhoven lens encoding. Lenses are exactly Store coalgebras: a -> Store b b with the right coherence laws.
OCaml Approach
In OCaml, Store is a record with a functional getter:
type ('s, 'a) store = { pos: 's; getter: 's -> 'a }
let extract { pos; getter } = getter pos
let seek s { getter; _ } = { pos = s; getter }
let peek s { getter; _ } = getter s
let extend f w =
{ pos = w.pos
; getter = fun s -> f { pos = s; getter = w.getter } }
let duplicate w =
{ pos = w.pos
; getter = fun s -> { pos = s; getter = w.getter } }
OCaml's polymorphic records make the types cleaner; Rust's Rc<dyn Fn> achieves the same but requires explicit sharing.
Full Source
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Deep Comparison
OCaml vs Rust: Store Comonad
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
fmap for Store<S, A> — map over the result type without changing the position.Store<(usize, usize), Cell> that represents a Game of Life grid and apply extend to compute one generation step.experiment: given a functor of positions F<S>, collect F<A> results by peeking at each position.Store s is equivalent to a coalgebra a -> s -> a paired with an s, connecting it to the lens definition.