ExamplesBy LevelBy TopicLearning Paths
242 Expert

Store Comonad

Functional Programming

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

  • • Understand Store as a pair (s -> a, s) — a getter and a current index
  • • Implement extract, extend, and duplicate for Store
  • • See how Store comonad relates to the Lens abstraction
  • • Explore seek (reposition) and peek (read at arbitrary position)
  • • Compare Store comonad with OCaml's equivalent using records and closures
  • Code Example

    #![allow(clippy::all)]
    // Stub — awaiting conversion from OCaml source.

    Key Differences

    AspectRustOCaml
    Getter sharingRc<dyn Fn(S) -> A>closure captured in record
    Clone constraintS: Clone requiredstructural copy for records
    extend lifetime'static bounds neededno lifetime tracking
    Lens connectionexplicit derivationdirectly via records
    Performancezero-cost with monomorphizationGC-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

    AspectOCamlRust
    Type systemHindley-MilnerOwnership + traits
    MemoryGCZero-cost abstractions
    MutabilityExplicit refmut keyword
    Error handlingOption/ResultResult<T, E>

    See README.md for detailed comparison.

    Exercises

  • Implement fmap for Store<S, A> — map over the result type without changing the position.
  • Verify the three comonad laws (left identity, right identity, associativity) with unit tests.
  • Build a 2D Store<(usize, usize), Cell> that represents a Game of Life grid and apply extend to compute one generation step.
  • Implement experiment: given a functor of positions F<S>, collect F<A> results by peeking at each position.
  • Show that Store s is equivalent to a coalgebra a -> s -> a paired with an s, connecting it to the lens definition.
  • Open Source Repos