🦀 Functional Rust
🎬 Closures in Rust Fn/FnMut/FnOnce, capturing environment, move closures, higher-order functions.
📝 Text version (for readers / accessibility)

• Closures capture variables from their environment — by reference, mutable reference, or by value (move)

• Three traits: Fn (shared borrow), FnMut (mutable borrow), FnOnce (takes ownership)

• Higher-order functions like .map(), .filter(), .fold() accept closures as arguments

• move closures take ownership of captured variables — essential for threading

• Closures enable functional patterns: partial application, composition, and strategy

📖 [View on hightechmind.io →](https://hightechmind.io/rust/001-higher-order-functions) ---

001-higher-order-functions — Higher Order Functions

See [hightechmind.io/rust/001-higher-order-functions](https://hightechmind.io/rust/001-higher-order-functions) for the full explanation, OCaml comparison, and tests.

Quick Start

cargo test

Files

// 001: Higher-Order Functions
// map, filter, fold — the three pillars of functional programming

// Approach 1: Using iterator methods
fn double_all(nums: &[i32]) -> Vec<i32> {
    nums.iter().map(|&x| x * 2).collect()
}

fn evens(nums: &[i32]) -> Vec<i32> {
    nums.iter().filter(|&&x| x % 2 == 0).copied().collect()
}

fn sum(nums: &[i32]) -> i32 {
    nums.iter().fold(0, |acc, &x| acc + x)
}

// Approach 2: Manual recursive implementations
fn my_map(f: fn(i32) -> i32, slice: &[i32]) -> Vec<i32> {
    if slice.is_empty() {
        vec![]
    } else {
        let mut result = vec![f(slice[0])];
        result.extend(my_map(f, &slice[1..]));
        result
    }
}

fn my_filter(pred: fn(i32) -> bool, slice: &[i32]) -> Vec<i32> {
    if slice.is_empty() {
        vec![]
    } else {
        let mut result = if pred(slice[0]) { vec![slice[0]] } else { vec![] };
        result.extend(my_filter(pred, &slice[1..]));
        result
    }
}

fn my_fold(f: fn(i32, i32) -> i32, acc: i32, slice: &[i32]) -> i32 {
    if slice.is_empty() {
        acc
    } else {
        my_fold(f, f(acc, slice[0]), &slice[1..])
    }
}

// Approach 3: Chained iterators
fn sum_of_doubled_evens(nums: &[i32]) -> i32 {
    nums.iter()
        .filter(|&&x| x % 2 == 0)
        .map(|&x| x * 2)
        .sum()
}

fn main() {
    let nums: Vec<i32> = (1..=10).collect();
    println!("double_all([1,2,3]) = {:?}", double_all(&[1, 2, 3]));
    println!("evens(1..10) = {:?}", evens(&nums));
    println!("sum(1..10) = {}", sum(&nums));
    println!("sum_of_doubled_evens(1..10) = {}", sum_of_doubled_evens(&nums));
}

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

    #[test]
    fn test_double_all() {
        assert_eq!(double_all(&[1, 2, 3]), vec![2, 4, 6]);
    }

    #[test]
    fn test_evens() {
        let nums: Vec<i32> = (1..=10).collect();
        assert_eq!(evens(&nums), vec![2, 4, 6, 8, 10]);
    }

    #[test]
    fn test_sum() {
        let nums: Vec<i32> = (1..=10).collect();
        assert_eq!(sum(&nums), 55);
    }

    #[test]
    fn test_my_map() {
        assert_eq!(my_map(|x| x + 1, &[1, 2, 3]), vec![2, 3, 4]);
    }

    #[test]
    fn test_my_filter() {
        assert_eq!(my_filter(|x| x > 3, &[1, 2, 3, 4, 5]), vec![4, 5]);
    }

    #[test]
    fn test_my_fold() {
        assert_eq!(my_fold(|a, b| a + b, 0, &[1, 2, 3]), 6);
    }

    #[test]
    fn test_sum_of_doubled_evens() {
        let nums: Vec<i32> = (1..=10).collect();
        assert_eq!(sum_of_doubled_evens(&nums), 60);
    }
}
(* 001: Higher-Order Functions *)
(* map, filter, fold — the three pillars of functional programming *)

(* Approach 1: Using standard library functions *)
let double_all lst = List.map (fun x -> x * 2) lst
let evens lst = List.filter (fun x -> x mod 2 = 0) lst
let sum lst = List.fold_left (fun acc x -> acc + x) 0 lst

(* Approach 2: Manual recursive implementations *)
let rec my_map f = function
  | [] -> []
  | x :: xs -> f x :: my_map f xs

let rec my_filter pred = function
  | [] -> []
  | x :: xs ->
    if pred x then x :: my_filter pred xs
    else my_filter pred xs

let rec my_fold_left f acc = function
  | [] -> acc
  | x :: xs -> my_fold_left f (f acc x) xs

(* Approach 3: Composition — combine HOFs *)
let sum_of_doubled_evens lst =
  lst
  |> List.filter (fun x -> x mod 2 = 0)
  |> List.map (fun x -> x * 2)
  |> List.fold_left ( + ) 0

(* Tests *)
let () =
  let nums = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] in
  assert (double_all [1; 2; 3] = [2; 4; 6]);
  assert (evens nums = [2; 4; 6; 8; 10]);
  assert (sum nums = 55);
  assert (my_map (fun x -> x + 1) [1; 2; 3] = [2; 3; 4]);
  assert (my_filter (fun x -> x > 3) [1; 2; 3; 4; 5] = [4; 5]);
  assert (my_fold_left ( + ) 0 [1; 2; 3] = 6);
  assert (sum_of_doubled_evens nums = 60);
  Printf.printf "✓ All tests passed\n"

📊 Detailed Comparison

Core Insight

Higher-order functions abstract iteration patterns. OCaml uses `List.map`, `List.filter`, `List.fold_left` on linked lists. Rust uses `.iter().map()`, `.filter()`, `.fold()` on iterator chains.

OCaml Approach

  • `List.map f lst` applies `f` to every element
  • `List.filter pred lst` keeps elements where `pred` is true
  • `List.fold_left f acc lst` reduces left-to-right
  • Functions are curried by default — partial application is free

Rust Approach

  • `.iter().map(|x| ...)` with closures
  • `.iter().filter(|x| ...)` — note double reference `&&x`
  • `.iter().fold(init, |acc, x| ...)` — accumulator first
  • Closures capture environment; `Fn`, `FnMut`, `FnOnce` traits

Comparison Table

FeatureOCamlRust
Map`List.map f lst``.iter().map(\x\f(x))`
Filter`List.filter p lst``.iter().filter(\x\p(x))`
Fold`List.fold_left f a lst``.iter().fold(a, \acc, x\...)`
CurryingNativeClosures returning closures
EvaluationEager (list)Lazy (iterator chain)