ExamplesBy LevelBy TopicLearning Paths
243 Expert

Environment Comonad

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "Environment Comonad" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. The Environment comonad (also called the Reader comonad's dual, or Co-Reader) pairs a value with a fixed environment: `(e, a)`. Key difference from OCaml: | Aspect | Rust | OCaml |

Tutorial

The Problem

The Environment comonad (also called the Reader comonad's dual, or Co-Reader) pairs a value with a fixed environment: (e, a). You can always extract the value, ask what the environment is, and extend computations that depend on both the current value and the surrounding environment. This models read-only context propagation where each step in a computation can inspect a shared environment without passing it explicitly.

🎯 Learning Outcomes

  • • Understand Env as the categorical dual of the Reader monad
  • • Implement extract, extend, and duplicate for the Env comonad
  • • See how ask retrieves the environment and local modifies it
  • • Compare the Env comonad with OCaml's equivalent using tuples and modules
  • • Recognize when Env comonad is more natural than threading an explicit config argument
  • Code Example

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

    Key Differences

    AspectRustOCaml
    Environment sharingE: Clone on each operationimplicit GC sharing
    Local transformationreturns Env<E2, A> (new type)returns same env type
    Duplicaterequires A: Clonestructural copy
    Composition.extend(f).extend(g) chainssame, pipe-friendly
    Adjunctiondual to State monadsame theoretical dual

    The Env comonad is adjoint to the State monad: Env extracts a value from context while State injects a state into continuation. Together they form the (- × e) ⊣ (e →) adjunction.

    OCaml Approach

    OCaml represents Env as a plain pair:

    type ('e, 'a) env = { env: 'e; val_: 'a }
    
    let extract { val_; _ } = val_
    let ask { env; _ } = env
    
    let extend f w = { env = w.env; val_ = f w }
    let duplicate w = { env = w.env; val_ = w }
    let local f w = { env = f w.env; val_ = w.val_ }
    

    OCaml's implicit polymorphism avoids the Clone constraints Rust requires. The tradeoff is that OCaml's type inference handles the variance silently while Rust makes it explicit.

    Full Source

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

    Deep Comparison

    OCaml vs Rust: Env 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 Env<E, A> that maps the value while keeping the environment unchanged.
  • Verify the comonad laws: extend extract = id, extract . extend f = f, extend f . extend g = extend (f . extend g).
  • Build a dependency injection container using Env<AppConfig, Service> where each extend step configures a new service layer.
  • Implement asks: given a function E -> B, produce Env<E, B> — the comonadic equivalent of Reader's asks.
  • Show the adjunction between Env and State by implementing unit and counit of the adjunction and checking the triangle identities.
  • Open Source Repos