Catamorphism
Tutorial Video
Text description (accessibility)
This video demonstrates the "Catamorphism" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. A catamorphism (fold/cata) is a generalized fold over a recursive data structure. Key difference from OCaml: 1. **HKT requirement**: These morphisms ideally require higher
Tutorial
The Problem
A catamorphism (fold/cata) is a generalized fold over a recursive data structure. Any fold can be expressed as a catamorphism. The F-algebra (algebra of the base functor) specifies how to collapse one level; the catamorphism applies it recursively bottom-up. This generalizes List.fold_right, tree fold, and any recursive descent. The term comes from Meijer et al. 1991 Bananas, Lenses, Envelopes and Barbed Wire.
🎯 Learning Outcomes
Code Example
#![allow(clippy::all)]
//! # Catamorphism (Fold)
//! Generalized fold over recursive structures.
pub fn cata_list<A, B>(list: &[A], nil: B, cons: impl Fn(&A, B) -> B) -> B {
list.iter().rev().fold(nil, |acc, x| cons(x, acc))
}
pub fn sum(xs: &[i32]) -> i32 {
cata_list(xs, 0, |x, acc| x + acc)
}
pub fn product(xs: &[i32]) -> i32 {
cata_list(xs, 1, |x, acc| x * acc)
}
pub fn length<A>(xs: &[A]) -> usize {
cata_list(xs, 0, |_, acc| acc + 1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sum() {
assert_eq!(sum(&[1, 2, 3]), 6);
}
#[test]
fn test_product() {
assert_eq!(product(&[1, 2, 3, 4]), 24);
}
#[test]
fn test_length() {
assert_eq!(length(&[1, 2, 3]), 3);
}
}Key Differences
recursion-schemes are widely used; in Rust and OCaml, direct recursion is more common in practice.OCaml Approach
OCaml's pattern matching and recursive types make morphism implementations natural. The Fix type and F-algebra/coalgebra patterns translate directly, though without Haskell's typeclass machinery:
(* OCaml recursive schemes use:
- Recursive variant types for F-algebras
- Higher-order functions for the morphism
- GADTs for type-safe fixed points in advanced cases *)
Full Source
#![allow(clippy::all)]
//! # Catamorphism (Fold)
//! Generalized fold over recursive structures.
pub fn cata_list<A, B>(list: &[A], nil: B, cons: impl Fn(&A, B) -> B) -> B {
list.iter().rev().fold(nil, |acc, x| cons(x, acc))
}
pub fn sum(xs: &[i32]) -> i32 {
cata_list(xs, 0, |x, acc| x + acc)
}
pub fn product(xs: &[i32]) -> i32 {
cata_list(xs, 1, |x, acc| x * acc)
}
pub fn length<A>(xs: &[A]) -> usize {
cata_list(xs, 0, |_, acc| acc + 1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sum() {
assert_eq!(sum(&[1, 2, 3]), 6);
}
#[test]
fn test_product() {
assert_eq!(product(&[1, 2, 3, 4]), 24);
}
#[test]
fn test_length() {
assert_eq!(length(&[1, 2, 3]), 3);
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sum() {
assert_eq!(sum(&[1, 2, 3]), 6);
}
#[test]
fn test_product() {
assert_eq!(product(&[1, 2, 3, 4]), 24);
}
#[test]
fn test_length() {
assert_eq!(length(&[1, 2, 3]), 3);
}
}
Deep Comparison
Catamorphism
Fold: tear down structure bottom-up