Coyoneda
Tutorial Video
Text description (accessibility)
This video demonstrates the "Coyoneda" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. While the Yoneda lemma gives a free Functor for any type constructor from the "contravariant" side, Coyoneda gives a free Functor from the "covariant" side. Key difference from OCaml: 1. **GADT vs. Any**: OCaml's GADT existential keeps the type information in the pattern match; Rust's `Box<dyn Any>` erases it and requires downcasting.
Tutorial
The Problem
While the Yoneda lemma gives a free Functor for any type constructor from the "contravariant" side, Coyoneda gives a free Functor from the "covariant" side. Coyoneda<F, A> is an existential type that wraps a value F<B> and a function B -> A, deferring the fmap until it is needed. The practical use: you can make any type constructor a Functor for free using Coyoneda, even if it does not natively support map. This is the foundation of the free applicative and free monad.
🎯 Learning Outcomes
map for any type constructorCoyoneda<F, A> = exists B. (F<B>, B -> A)map calls without evaluating the underlying functorCode Example
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Key Differences
Box<dyn Any> erases it and requires downcasting.F regardless of whether F supports fmap; this is useful for uninspectable data sources.map calls into a function composition — O(1) per map call; evaluation is deferred until run.fmap.OCaml Approach
OCaml's Coyoneda uses GADT existentials:
type 'a 'f coyoneda = Coyoneda : 'b 'f * ('b -> 'a) -> 'a 'f coyoneda
let lift fb = Coyoneda (fb, Fun.id)
let map f (Coyoneda (fb, g)) = Coyoneda (fb, f >> g)
let run (Coyoneda (fb, f)) = map f fb (* requires F to be a Functor *)
The GADT hides 'b — the existential type — while preserving the function 'b -> 'a. Map fusion is compositional: each map just extends the function.
Full Source
#![allow(clippy::all)]
// Stub — awaiting conversion from OCaml source.Deep Comparison
OCaml vs Rust: Coyoneda
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
map for Coyoneda<F, A> and verify that applying 5 maps results in a single composed function.run: Coyoneda<Option, A> -> Option<A> that evaluates the deferred computation.Coyoneda provides a valid Functor instance: verify the identity and composition laws.