ExamplesBy LevelBy TopicLearning Paths
613 Fundamental

Futumorphism

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "Futumorphism" functional Rust example. Difficulty level: Fundamental. Key concepts covered: Functional Programming. A futumorphism (futu) is the dual of a histomorphism — an anamorphism that can look ahead multiple levels into the future structure being built. Key difference from OCaml: 1. **HKT requirement**: These morphisms ideally require higher

Tutorial

The Problem

A futumorphism (futu) is the dual of a histomorphism — an anamorphism that can look ahead multiple levels into the future structure being built. It uses a free monad of the base functor as the coalgebra target, allowing the generator to produce multiple levels of structure at once. This is useful for expanding macros, generating tree structures, and producing ahead-of-need outputs.

🎯 Learning Outcomes

  • • The categorical definition and the mathematical laws that must hold
  • • How to implement this pattern in Rust despite the lack of higher-kinded types
  • • The relationship to more familiar functional idioms (fold, unfold, map)
  • • Key concepts: futu, look-ahead unfold, Free monad coalgebra
  • • Where this pattern appears in production systems and when simpler alternatives suffice
  • Code Example

    #![allow(clippy::all)]
    //! # Futumorphism
    //! Unfold that can produce multiple layers at once.
    
    pub fn futu<S, A>(seed: S, step: impl Fn(S) -> FutuStep<A, S>) -> Vec<A> {
        let mut result = Vec::new();
        let mut s = seed;
        loop {
            match step(s) {
                FutuStep::Done => break,
                FutuStep::One(a, next) => {
                    result.push(a);
                    s = next;
                }
                FutuStep::Two(a, b, next) => {
                    result.push(a);
                    result.push(b);
                    s = next;
                }
            }
        }
        result
    }
    
    pub enum FutuStep<A, S> {
        Done,
        One(A, S),
        Two(A, A, S),
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
        #[test]
        fn test_futu() {
            let xs = futu(0, |n| {
                if n >= 4 {
                    FutuStep::Done
                } else {
                    FutuStep::One(n, n + 1)
                }
            });
            assert_eq!(xs, vec![0, 1, 2, 3]);
        }
    }

    Key Differences

  • HKT requirement: These morphisms ideally require higher-kinded types for full generality; Rust uses GATs or associated types as approximations.
  • Performance: Rust's implementations are more verbose but compile to efficient machine code; OCaml's implementations are more concise with similar runtime performance.
  • Practical adoption: In Haskell, recursive schemes from recursion-schemes are widely used; in Rust and OCaml, direct recursion is more common in practice.
  • Theoretical value: Understanding these patterns deepens intuition for all recursive programming, even when direct recursion is used in production code.
  • 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)]
    //! # Futumorphism
    //! Unfold that can produce multiple layers at once.
    
    pub fn futu<S, A>(seed: S, step: impl Fn(S) -> FutuStep<A, S>) -> Vec<A> {
        let mut result = Vec::new();
        let mut s = seed;
        loop {
            match step(s) {
                FutuStep::Done => break,
                FutuStep::One(a, next) => {
                    result.push(a);
                    s = next;
                }
                FutuStep::Two(a, b, next) => {
                    result.push(a);
                    result.push(b);
                    s = next;
                }
            }
        }
        result
    }
    
    pub enum FutuStep<A, S> {
        Done,
        One(A, S),
        Two(A, A, S),
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
        #[test]
        fn test_futu() {
            let xs = futu(0, |n| {
                if n >= 4 {
                    FutuStep::Done
                } else {
                    FutuStep::One(n, n + 1)
                }
            });
            assert_eq!(xs, vec![0, 1, 2, 3]);
        }
    }
    ✓ Tests Rust test suite
    #[cfg(test)]
    mod tests {
        use super::*;
        #[test]
        fn test_futu() {
            let xs = futu(0, |n| {
                if n >= 4 {
                    FutuStep::Done
                } else {
                    FutuStep::One(n, n + 1)
                }
            });
            assert_eq!(xs, vec![0, 1, 2, 3]);
        }
    }

    Deep Comparison

    Futumorphism

    Unfold producing multiple layers

    Exercises

  • Laws verification: Write tests that verify the categorical laws for this morphism on a specific data type.
  • New data type: Apply the morphism to a different recursive data type (e.g., apply catamorphism to a rose tree instead of a binary tree).
  • Comparison: Implement the same computation using direct recursion and the morphism — measure whether the morphism version composes more cleanly.
  • Open Source Repos