ExamplesBy LevelBy TopicLearning Paths
843 Advanced

Generic Memoization

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "Generic Memoization" functional Rust example. Difficulty level: Advanced. Key concepts covered: Functional Programming. Recursive functions with overlapping subproblems waste exponential time recomputing the same results. Key difference from OCaml: | Aspect | Rust | OCaml |

Tutorial

The Problem

Recursive functions with overlapping subproblems waste exponential time recomputing the same results. Memoization wraps a function with a cache: on the first call with given arguments, compute and store the result; on subsequent calls, return the cached value. While specific DP algorithms hard-code their memoization tables, generic memoization provides a reusable cache wrapper for any pure function. This pattern is fundamental in functional languages (Haskell's memoize, OCaml's Hashtbl-based wrappers) and enables transparent DP without restructuring code. Real-world uses: web request caching, computed property memoization in UI frameworks, and expensive query result caching.

🎯 Learning Outcomes

  • • Implement a HashMap-backed memoizer that wraps any Fn(K) -> V where K is hashable
  • • Handle recursive memoization using RefCell<HashMap> for interior mutability
  • • Understand the challenge: recursive memoized functions cannot easily call themselves through the cache
  • • Apply memoization to Fibonacci, LCS, and graph shortest paths to see exponential → polynomial speedup
  • • Recognize the difference from tabulation: memoization is top-down and lazy; tabulation is bottom-up and eager
  • Code Example

    #![allow(clippy::all)]
    //! Placeholder

    Key Differences

    AspectRustOCaml
    Interior mutabilityRefCell<HashMap>Hashtbl (inherently mutable)
    Recursive wrapper&Self second argref to function
    Key constraintEq + Hash + CloneHashtbl equality
    Thread safetyUse Mutex<HashMap> insteadNot needed for single-threaded
    EvictionManual HashMap::retainWeak.t for GC integration
    Lazy vs eagerLazy (top-down)Same

    OCaml Approach

    OCaml memoization is simpler: let memoize f = let tbl = Hashtbl.create 16 in fun x -> match Hashtbl.find_opt tbl x with Some v -> v | None -> let v = f x in Hashtbl.add tbl x v; v. Recursive memoization uses a ref for the function: let rec_memo f = let r = ref (fun _ -> assert false) in let m = memoize (fun x -> f !r x) in r := m; m. OCaml's first-class mutability makes this straightforward. The Weak.t module enables cache eviction for memory-constrained situations.

    Full Source

    #![allow(clippy::all)]
    //! Placeholder

    Deep Comparison

    OCaml vs Rust: Memoization Generic

    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

  • Implement thread-safe memoization using Arc<Mutex<HashMap>> and measure the synchronization overhead.
  • Add a cache eviction policy: LRU (evict least recently used) or LFU (evict least frequently used).
  • Implement memoize_recursive that allows the function to call itself via the memoized wrapper without &Self threading.
  • Benchmark memoized Fibonacci(50) vs. tabulated DP and compare code clarity.
  • Implement memoization with TTL (time-to-live): entries expire after a configurable duration.
  • Open Source Repos