Anamorphism
Tutorial Video
Text description (accessibility)
This video demonstrates the "Anamorphism" functional Rust example. Difficulty level: Expert. Key concepts covered: Functional Programming. An anamorphism (unfold/ana) is the categorical dual of a catamorphism — it builds a recursive structure top-down from a seed. Key difference from OCaml: 1. **HKT requirement**: These morphisms ideally require higher
Tutorial
The Problem
An anamorphism (unfold/ana) is the categorical dual of a catamorphism — it builds a recursive structure top-down from a seed. While catamorphisms consume structures, anamorphisms produce them. The F-coalgebra specifies how to expand one level from a seed value. Examples: generating a list from a range, unfolding a tree from a depth-first generator, producing a stream from a state.
🎯 Learning Outcomes
Code Example
#![allow(clippy::all)]
//! # Anamorphism (Unfold)
//! Generalized unfold to build recursive structures.
pub fn ana<S, A>(seed: S, next: impl Fn(S) -> Option<(A, S)>) -> Vec<A> {
let mut result = Vec::new();
let mut s = seed;
while let Some((a, s2)) = next(s) {
result.push(a);
s = s2;
}
result
}
pub fn range(start: i32, end: i32) -> Vec<i32> {
ana(start, |n| if n < end { Some((n, n + 1)) } else { None })
}
pub fn iterate<A: Clone>(init: A, f: impl Fn(&A) -> A, n: usize) -> Vec<A> {
ana((init, n), |(a, count)| {
if count > 0 {
Some((a.clone(), (f(&a), count - 1)))
} else {
None
}
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_range() {
assert_eq!(range(0, 5), vec![0, 1, 2, 3, 4]);
}
#[test]
fn test_iterate() {
assert_eq!(iterate(1, |x| x * 2, 4), vec![1, 2, 4, 8]);
}
}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)]
//! # Anamorphism (Unfold)
//! Generalized unfold to build recursive structures.
pub fn ana<S, A>(seed: S, next: impl Fn(S) -> Option<(A, S)>) -> Vec<A> {
let mut result = Vec::new();
let mut s = seed;
while let Some((a, s2)) = next(s) {
result.push(a);
s = s2;
}
result
}
pub fn range(start: i32, end: i32) -> Vec<i32> {
ana(start, |n| if n < end { Some((n, n + 1)) } else { None })
}
pub fn iterate<A: Clone>(init: A, f: impl Fn(&A) -> A, n: usize) -> Vec<A> {
ana((init, n), |(a, count)| {
if count > 0 {
Some((a.clone(), (f(&a), count - 1)))
} else {
None
}
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_range() {
assert_eq!(range(0, 5), vec![0, 1, 2, 3, 4]);
}
#[test]
fn test_iterate() {
assert_eq!(iterate(1, |x| x * 2, 4), vec![1, 2, 4, 8]);
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_range() {
assert_eq!(range(0, 5), vec![0, 1, 2, 3, 4]);
}
#[test]
fn test_iterate() {
assert_eq!(iterate(1, |x| x * 2, 4), vec![1, 2, 4, 8]);
}
}
Deep Comparison
Anamorphism
Unfold: build structure from seed