๐Ÿฆ€ Functional Rust
๐ŸŽฌ Rust Ownership in 30 seconds Visual walkthrough of ownership, moves, and automatic memory management.
๐Ÿ“ Text version (for readers / accessibility)

โ€ข Each value in Rust has exactly one owner โ€” when the owner goes out of scope, the value is dropped

โ€ข Assignment moves ownership by default; the original binding becomes invalid

โ€ข Borrowing (&T / &mut T) lets you reference data without taking ownership

โ€ข The compiler enforces: many shared references OR one mutable reference, never both

โ€ข No garbage collector needed โ€” memory is freed deterministically at scope exit

542: Higher-Ranked Trait Bounds (for<'a>)

Difficulty: 5 Level: Advanced `for<'a>` means "for any possible lifetime 'a." It's universal quantification over lifetimes. Use it when you need a callback that works with references of any duration โ€” not just one specific lifetime.

The Problem This Solves

Without `for<'a>`, a callback's lifetime is fixed at the call site. This causes problems when you want to store a closure that will process references with different lifetimes at different times:
// Fixed 'a: the closure only works for one specific lifetime
fn apply_fixed<'a, F>(f: F, s: &'a str) -> &'a str
where
 F: Fn(&'a str) -> &'a str,  // F is tied to THIS specific 'a
{ f(s) }
Try to store that closure in a struct and use it with different strings over time โ€” you can't. The `'a` was fixed when you wrote the function. You need a closure that promises to work for any `'a`:
// HRTB: F works for any lifetime, not just one specific one
struct Processor {
 transform: Box<dyn for<'a> Fn(&'a str) -> &'a str>,
}
// Now transform can be called with a string of any duration

The Intuition

A regular generic `<'a, F: Fn(&'a str) -> &'a str>` says: "pick a specific `'a` at the call site, and F must work for that `'a`." `for<'a> Fn(&'a str) -> &'a str` says: "F must work for every possible `'a`." It's a stronger requirement on F โ€” F can't cheat by only working for long-lived references. It has to handle references that live for one nanosecond or one year. This is why closures like `|s: &str| s.trim()` satisfy `for<'a>` bounds โ€” they're genuinely lifetime-agnostic. Closures that capture a reference of a specific lifetime do not โ€” they're tied to that capture's scope.

How It Works in Rust

The syntax:
// Read as: "F implements Fn for any lifetime 'a"
fn apply_hrtb<F>(f: F, s: &str) -> String
where
 F: for<'a> Fn(&'a str) -> &'a str,  // works for ANY 'a
{
 f(s).to_string()
}

// Equivalent shorthand (compiler infers HRTB for simple cases):
fn apply_hrtb<F: Fn(&str) -> &str>(f: F, s: &str) -> String {
 f(s).to_string()
}
Stored in a struct:
struct Processor {
 transform: Box<dyn for<'a> Fn(&'a str) -> &'a str>,
}

impl Processor {
 fn new(f: impl for<'a> Fn(&'a str) -> &'a str + 'static) -> Self {
     Processor { transform: Box::new(f) }
 }

 fn process<'a>(&self, input: &'a str) -> &'a str {
     (self.transform)(input)  // works regardless of input's lifetime
 }
}

// A closure that's lifetime-agnostic works:
let p = Processor::new(|s: &str| s.trim());

// Call with any lifetime โ€” all work:
let owned = String::from("  hello  ");
println!("{}", p.process(&owned));     // 'a = owned's lifetime
println!("{}", p.process("literal"));  // 'a = 'static
Used in generic iterators:
fn map_all<T, F>(items: &[T], f: F) -> Vec<String>
where
 F: for<'a> Fn(&'a T) -> String,
{
 items.iter().map(|x| f(x)).collect()
}

// Works because for<'a> Fn(&'a T) means the closure handles elements of any lifetime
let nums = vec![1, 2, 3];
let s = map_all(&nums, |n| format!("{}", n));
When the compiler infers HRTB automatically:
// You usually don't need to write for<'a> explicitly
// The compiler infers it from usage:
fn apply<F: Fn(&str) -> usize>(f: F, s: &str) -> usize { f(s) }
// This is equivalent to: F: for<'a> Fn(&'a str) -> usize

What This Unlocks

Key Differences

ConceptOCamlRust
Higher-order functionsParametric polymorphism handles this naturallyLifetime polymorphism requires explicit `for<'a>` when closure arguments involve references
Rank-2 polymorphism`let f : (type a. a -> a) = fun x -> x``for<'a> Fn(&'a T) -> &'a U` โ€” rank-2 quantification over lifetimes
Storing generic callbacksFunctors and modules handle thisHRTB enables erasing a lifetime-polymorphic closure into a trait object
Type inferenceFull HM inference handles rank-1 typesHRTB needs explicit `for<'a>` in complex cases; inferred for simple `Fn(&T)`
Functor patternType class / module-basedHRTB `for<'a> Fn(&'a T) -> &'a U` is the Rust equivalent for reference-in, reference-out
//! # 542. Higher-Ranked Trait Bounds (for<'a>)
//! Universal quantification over lifetimes for maximally flexible callbacks.

/// Without HRTB: lifetime 'a is fixed at the call site
/// This works for one specific 'a
fn apply_fixed<'a, F>(f: F, s: &'a str) -> &'a str
where
    F: Fn(&'a str) -> &'a str,
{
    f(s)
}

/// With HRTB: F works for ANY lifetime
/// The closure must handle references of any lifetime
fn apply_hrtb<F>(f: F, s: &str) -> String
where
    F: for<'a> Fn(&'a str) -> &'a str,
{
    f(s).to_string()
}

/// HRTB in a struct: store a callback that works with any lifetime
struct Processor {
    transform: Box<dyn for<'a> Fn(&'a str) -> &'a str>,
}

impl Processor {
    fn new(f: impl for<'a> Fn(&'a str) -> &'a str + 'static) -> Self {
        Processor { transform: Box::new(f) }
    }

    fn process<'a>(&self, input: &'a str) -> &'a str {
        (self.transform)(input)
    }
}

/// HRTB with Fn returning owned (no lifetime in output)
fn map_strings<F>(strings: &[String], f: F) -> Vec<String>
where
    F: for<'a> Fn(&'a str) -> String,
{
    strings.iter().map(|s| f(s.as_str())).collect()
}

/// Most common HRTB usage: passing closures to generic iterators
fn apply_to_all<T, F>(items: &[T], f: F) -> Vec<String>
where
    F: for<'a> Fn(&'a T) -> String,
{
    items.iter().map(|x| f(x)).collect()
}

fn main() {
    // HRTB in a free function
    let result = apply_hrtb(|s| s.trim(), "  hello world  ");
    println!("trimmed: {:?}", result);

    // The closure works for any 'a โ€” shown by using it with different lifetimes
    let f: &(dyn for<'a> Fn(&'a str) -> &'a str) = &|s: &str| {
        if s.is_empty() { "empty" } else { s }
    };

    let s1 = String::from("hello");
    let s2 = String::from("world");
    println!("f(s1): {}", f(&s1));
    println!("f(s2): {}", f(&s2));
    println!("f(literal): {}", f("literal"));

    // HRTB in struct
    let processor = Processor::new(|s: &str| {
        // Works for any lifetime 'a
        s.trim()
    });

    let owned = String::from("  hello  ");
    println!("processed: {:?}", processor.process(&owned));
    {
        let temp = String::from("  temp  ");
        println!("temp processed: {:?}", processor.process(&temp));
    }

    // Map strings with HRTB closure
    let strings = vec!["hello".to_string(), "world".to_string(), "rust".to_string()];
    let uppers = map_strings(&strings, |s| s.to_uppercase());
    println!("uppers: {:?}", uppers);

    // apply_to_all
    let nums = vec![1i32, 2, 3, 4, 5];
    let formatted = apply_to_all(&nums, |n| format!("num:{}", n));
    println!("formatted: {:?}", formatted);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_apply_hrtb() {
        let result = apply_hrtb(|s| s.trim(), "  test  ");
        assert_eq!(result, "test");
    }

    #[test]
    fn test_processor_hrtb() {
        let p = Processor::new(|s: &str| if s.len() > 5 { &s[..5] } else { s });
        let s = String::from("hello world");
        assert_eq!(p.process(&s), "hello");
    }

    #[test]
    fn test_map_strings_hrtb() {
        let v = vec!["a".to_string(), "bb".to_string()];
        let lens = map_strings(&v, |s| s.len().to_string());
        assert_eq!(lens, vec!["1", "2"]);
    }
}
(* Higher-ranked types in OCaml using polymorphic record fields *)
(* Standard OCaml doesn't have rank-2 types without the forall trick *)

(* Simulating: a function that works for ANY type *)
type 'a identity = { apply: 'a -> 'a }
(* But we want โˆ€'a. 'a -> 'a: *)
type universal_id = { apply: 'a. 'a -> 'a }

let id = { apply = fun x -> x }

let () =
  Printf.printf "id int: %d\n" (id.apply 42);
  Printf.printf "id str: %s\n" (id.apply "hello");

  (* Polymorphic function applied to different types *)
  let process_with f =
    let s = f "hello" in
    let n = f 42 in  (* would fail without rank-2! *)
    ignore (s, n)
  in
  ignore process_with  (* OCaml can't do this without forall trick *)