ExamplesBy LevelBy TopicLearning Paths
249 Expert

Monad from Adjunction

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "Monad from Adjunction" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. Every adjunction `F ⊣ G` gives rise to a monad `G ∘ F` with unit `η` and multiplication `G(ε_F)`, and a comonad `F ∘ G` with counit `ε` and comultiplication `F(η_G)`. Key difference from OCaml: | Aspect | Rust | OCaml |

Tutorial

The Problem

Every adjunction F ⊣ G gives rise to a monad G ∘ F with unit η and multiplication G(ε_F), and a comonad F ∘ G with counit ε and comultiplication F(η_G). This is the deepest connection between adjunctions, monads, and comonads. The State monad arises from the product/exponential adjunction; the List monad from the free/forgetful adjunction. This example derives the State monad and its dual the Env comonad from first principles using the product adjunction.

🎯 Learning Outcomes

  • • Derive the State monad as G ∘ F where F = (- × S) and G = (S → -)
  • • Implement return as the adjunction unit η and join as G(ε_F)
  • • Derive the Env comonad as F ∘ G from the same adjunction
  • • Verify that the monad laws follow from the adjunction coherence conditions
  • • Compare this systematic derivation with OCaml's more direct categorical encoding
  • Code Example

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

    Key Differences

    AspectRustOCaml
    Adjunction encodingtraits + structsmodule signatures
    join derivationmanual Box wrappingdirect function application
    Monad lawsrequire S: Clone + 'staticimplicit polymorphism
    Law verificationruntime testsqcheck property tests
    Generalityproduct adjunction onlyfull module parametricity

    This derivation demonstrates that State and Env are not ad-hoc constructions but arise necessarily and uniquely from the product adjunction, with no choices involved.

    OCaml Approach

    OCaml's module system makes the adjunction derivation structurally cleaner:

    module type ADJUNCTION = sig
      type s
      (* F A = (A * s), G B = s -> B *)
      val unit   : 'a -> s -> ('a * s)   (* eta *)
      val counit : (s -> 'b) * s -> 'b   (* epsilon *)
    end
    
    (* Derived monad: G o F A = s -> (A * s) *)
    let return_ a s = (a, s)
    let join mma s = let (ma, s') = mma s in ma s'
    let bind ma f s = let (a, s') = ma s in f a s'
    
    (* Derived comonad: F o G B = (s -> B) * s *)
    let extract (f, s) = f s
    let duplicate (f, s) = (fun s' -> (f, s'), s)
    

    Full Source

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

    Deep Comparison

    OCaml vs Rust: Monad From Adjunction

    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

  • Derive the Writer<W> monad from the adjunction (- × W) ⊣ (W →) where W is a monoid; implement tell, listen, and pass.
  • Verify the monad laws for the derived State monad using property tests: left identity, right identity, and associativity.
  • Derive the Reader<R> monad from the diagonal/product adjunction and implement ask and local.
  • Implement the monad morphism from State<S, A> to Reader<S, (A, S)> (which is just the function type) and show it respects return and bind.
  • Show that the unit η and counit ε of the adjunction satisfy the triangle identities computationally by writing tests that check G(ε) ∘ ηG = idG and ε_F ∘ F(η) = idF.
  • Open Source Repos