๐Ÿฆ€ 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

510: Currying Pattern in Rust

Difficulty: 3 Level: Intermediate Transform multi-argument functions into chains of single-argument functions: `add(3, 4)` becomes `add(3)(4)`.

The Problem This Solves

You want to use `map` with a two-argument function, but `map` only passes one argument per call. In OCaml or Haskell, this is trivial โ€” all functions are curried by default, so `map (add 5) [1;2;3]` just works. In Rust, you reach for a closure: `map(|x| add(5, x), ...)`. The deeper problem appears when you need to compose or partially apply many multi-argument functions. The manual closure wrapping accumulates, making code verbose. Currying solves this structurally: a curried function is its own partial application mechanism. Understanding currying also demystifies function type signatures in type theory, makes closures-as-return-values feel natural, and helps you recognize patterns in Rust APIs that implicitly curry (like `sort_by_key`).

The Intuition

Currying is named after Haskell Curry (the logician, not the food). The idea: instead of `f(a, b) = result`, you have `f(a) = g` where `g(b) = result`. You transform a function of N arguments into N nested single-argument functions. In OCaml, `let add a b = a + b` is automatically `add : int -> int -> int` โ€” a function that takes an `int` and returns a function `int -> int`. You get partial application for free: `let add5 = add 5`. In Rust, you make this explicit with nested closures. Each closure captures the previous arguments via `move` and returns another closure. It's more verbose than OCaml but the mechanics are identical.

How It Works in Rust

// Curried add: add(x)(y) instead of add(x, y)
fn add(x: i32) -> impl Fn(i32) -> i32 {
 move |y| x + y    // x captured by move
}

let add5 = add(5);      // add5: impl Fn(i32) -> i32
println!("{}", add5(3));  // 8
println!("{}", add(3)(4)); // 7 โ€” chained call

// Three-argument curried function: clamp(lo)(hi)(x)
// impl Fn -> impl Fn doesn't compile, so use Box<dyn Fn>
fn clamp(lo: i32) -> Box<dyn Fn(i32) -> Box<dyn Fn(i32) -> i32>> {
 Box::new(move |hi| Box::new(move |x| x.max(lo).min(hi)))
}

let clamp_0_100 = clamp(0)(100);  // partially applied โ€” lo and hi fixed
println!("{}", clamp_0_100(150));  // 100 โ€” clamped
println!("{}", clamp_0_100(42));   //  42 โ€” unchanged

// Convert uncurried to curried generically
fn curry<A: Copy + 'static, B: Copy + 'static, C: 'static, F>(
 f: F
) -> Box<dyn Fn(A) -> Box<dyn Fn(B) -> C>>
where F: Fn(A, B) -> C + Copy + 'static {
 Box::new(move |a| Box::new(move |b| f(a, b)))
}

let curried_mul = curry(|x: i32, y: i32| x * y);
let times6 = curried_mul(6);
println!("{}", times6(7));  // 42

// Convert curried back to uncurried
fn uncurry<A, B, C, F, G>(f: F) -> impl Fn(A, B) -> C
where F: Fn(A) -> G, G: Fn(B) -> C {
 move |a, b| f(a)(b)
}
let plain_add = uncurry(add);
println!("{}", plain_add(3, 4)); // 7

What This Unlocks

Key Differences

ConceptOCamlRust
Curried by defaultYes โ€” every functionNo โ€” must explicitly nest closures
Partial application`let add5 = add 5` โ€” automatic`let add5 = add(5)` โ€” only if curried
Type signature`int -> int -> int``impl Fn(i32) -> impl Fn(i32) -> i32`
Multi-level returnNatural with type inferenceNeeds `Box<dyn Fn>` for 3+ levels
`curry` helper`let curry f a b = f (a, b)`Generic function or macro
//! # 510. Currying Pattern in Rust
//! Explicit currying via nested closures returning closures.

/// Curried add: add(x)(y) = x + y
fn add(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x + y
}

/// Curried multiply: mul(x)(y) = x * y
fn mul(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x * y
}

/// Three-argument curried clamp: clamp(lo)(hi)(x)
/// Uses Box<dyn Fn> because nested impl Fn -> impl Fn isn't allowed
fn clamp(lo: i32) -> Box<dyn Fn(i32) -> Box<dyn Fn(i32) -> i32>> {
    Box::new(move |hi| Box::new(move |x| x.max(lo).min(hi)))
}

/// Convert a 2-arg uncurried function to curried form
/// Uses Box<dyn Fn> for the outer return to allow nested return type
fn curry<A: Copy + 'static, B: Copy + 'static, C: 'static, F>(f: F) -> Box<dyn Fn(A) -> Box<dyn Fn(B) -> C>>
where
    F: Fn(A, B) -> C + Copy + 'static,
{
    Box::new(move |a| Box::new(move |b| f(a, b)))
}

/// Convert a curried function back to uncurried
fn uncurry<A, B, C, F, G>(f: F) -> impl Fn(A, B) -> C
where
    F: Fn(A) -> G,
    G: Fn(B) -> C,
{
    move |a, b| f(a)(b)
}

fn main() {
    // Natural use of curried functions
    let add5 = add(5);
    let times3 = mul(3);
    println!("add5(10) = {}", add5(10));
    println!("times3(7) = {}", times3(7));

    // Chained call: curried style
    println!("add(3)(4) = {}", add(3)(4));
    println!("mul(6)(7) = {}", mul(6)(7));

    // Three-arg curried: clamp(0)(100)(x)
    let clamp_0_100 = clamp(0)(100);
    println!("clamp(0)(100)(150) = {}", clamp_0_100(150));
    println!("clamp(0)(100)(-5) = {}", clamp_0_100(-5));
    println!("clamp(0)(100)(42) = {}", clamp_0_100(42));

    // curry/uncurry conversion
    let uncurried_add = |x: i32, y: i32| x + y;
    let curried_add = curry(uncurried_add);
    let add7 = curried_add(7);
    println!("add7(3) = {}", add7(3));

    let back_to_uncurried = uncurry(add);
    println!("uncurried add(3, 4) = {}", back_to_uncurried(3, 4));

    // Point-free map with curried add
    let numbers = [1, 2, 3, 4, 5];
    let add10 = add(10);
    let result: Vec<i32> = numbers.iter().map(|&x| add10(x)).collect();
    println!("map add(10) [1..5] = {:?}", result);
}

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

    #[test]
    fn test_curried_add() {
        assert_eq!(add(5)(3), 8);
        let add10 = add(10);
        assert_eq!(add10(0), 10);
        assert_eq!(add10(5), 15);
    }

    #[test]
    fn test_curried_clamp() {
        let clamp_5_10 = clamp(5)(10);
        assert_eq!(clamp_5_10(7), 7);
        assert_eq!(clamp_5_10(2), 5);
        assert_eq!(clamp_5_10(15), 10);
    }

    #[test]
    fn test_curry() {
        let f = curry(|x: i32, y: i32| x * y);
        assert_eq!(f(6)(7), 42);
    }

    #[test]
    fn test_uncurry() {
        let g = uncurry(add);
        assert_eq!(g(3, 4), 7);
    }
}
(* Currying in OCaml โ€” natural, all functions are curried *)

(* Standard curried functions *)
let add x y = x + y
let multiply x y = x * y
let clamp lo hi x = max lo (min hi x)

(* Uncurried (tuple form) *)
let add_uncurried (x, y) = x + y

(* curry: convert uncurried to curried *)
let curry f x y = f (x, y)

(* uncurry: convert curried to uncurried *)
let uncurry f (x, y) = f x y

(* Flip argument order *)
let flip f x y = f y x

let () =
  (* Natural partial application via currying *)
  let add5 = add 5 in
  let times3 = multiply 3 in
  Printf.printf "add5(10) = %d\n" (add5 10);
  Printf.printf "times3(7) = %d\n" (times3 7);

  (* Three-arg curried function *)
  let clamp_0_100 = clamp 0 100 in
  Printf.printf "clamp_0_100(150) = %d\n" (clamp_0_100 150);

  (* curry/uncurry conversion *)
  let curried_add = curry add_uncurried in
  let add7 = curried_add 7 in
  Printf.printf "add7(3) = %d\n" (add7 3);

  (* Flip *)
  let sub = fun x y -> x - y in
  let rsub = flip sub in
  Printf.printf "rsub 3 10 = %d (10 - 3)\n" (rsub 3 10);

  (* Point-free pipeline using curried functions *)
  let process = List.map (add 10) [1;2;3;4;5] in
  Printf.printf "map (add 10) [1..5] = [%s]\n"
    (String.concat ";" (List.map string_of_int process))