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

509: Closure Composition

Difficulty: 3 Level: Intermediate Build complex transformations from simple pieces by chaining functions: `compose(f, g)(x) = f(g(x))`.

The Problem This Solves

You have three transformations: double a number, add 1, then square it. Without composition, you write one big function `|x| (x * 2 + 1).pow(2)` โ€” or worse, nested calls `square(add1(double(x)))` that read right-to-left and obscure the order of operations. As pipelines grow, so does the cognitive load of tracking what happens when. You want to name sub-transformations, test them independently, and combine them in different orders for different use cases. Composition lets you treat functions as building blocks. The deeper issue: as business logic grows, you want to express it as a sequence of named steps. Composition gives you this without inventing a framework โ€” just functions combining functions.

The Intuition

Function composition is math's `โˆ˜` operator: `(f โˆ˜ g)(x) = f(g(x))`. It's a right-to-left combinator. The pipe version is left-to-right: `pipe(f, g)(x) = g(f(x))` โ€” which reads like English: "first do f, then g." Python doesn't have built-in composition, but you'd write `compose = lambda f, g: lambda x: f(g(x))`. JavaScript: `const compose = (f, g) => x => f(g(x))`. In OCaml, `|>` pipes left-to-right and `@@` applies right-to-left. Rust provides neither natively but lets you build them. The result of composition is just another closure. Composing closures has zero runtime overhead โ€” the compiler inlines the whole chain.

How It Works in Rust

// compose: mathematical notation โ€” right-to-left (g applied first, then f)
fn compose<A, B, C, F, G>(f: F, g: G) -> impl Fn(A) -> C
where
 F: Fn(B) -> C,
 G: Fn(A) -> B,
{
 move |x| f(g(x))   // captures both f and g by move
}

// pipe: data-flow notation โ€” left-to-right (f applied first, then g)
fn pipe<A, B, C, F, G>(f: F, g: G) -> impl Fn(A) -> C
where
 F: Fn(A) -> B,
 G: Fn(B) -> C,
{
 move |x| g(f(x))
}

let double = |x: i32| x * 2;
let inc    = |x: i32| x + 1;
let square = |x: i32| x * x;

// compose(inc, double)(5) = inc(double(5)) = 11
let double_then_inc = compose(inc, double);
println!("{}", double_then_inc(5)); // 11

// pipe reads left-to-right: double(5)=10, inc(10)=11, square(11)=121
let process = pipe(pipe(double, inc), square);
println!("{}", process(5)); // 121

// Builder pattern for multi-step pipelines
struct Pipeline<T> {
 steps: Vec<Box<dyn Fn(T) -> T>>,
}
impl<T: 'static> Pipeline<T> {
 fn new() -> Self { Pipeline { steps: Vec::new() } }
 fn then(mut self, f: impl Fn(T) -> T + 'static) -> Self {
     self.steps.push(Box::new(f));
     self
 }
 fn run(self) -> impl Fn(T) -> T {
     move |x| self.steps.iter().fold(x, |acc, f| f(acc))
 }
}

let pipeline = Pipeline::new()
 .then(|x: i32| x * 2)  // step 1
 .then(|x| x + 1)        // step 2
 .then(|x| x * x)        // step 3
 .run();
println!("{}", pipeline(3)); // ((3*2)+1)^2 = 49

What This Unlocks

Key Differences

ConceptOCamlRust
Compose operatorCustom `( >> )` or `( << )`Custom `compose()` function
Mathematical `f โˆ˜ g``let compose f g x = f (g x)``fn compose<...>(f, g) -> impl Fn`
Pipe forward`\>` built-in operator`.pipe(f)` via extension trait or custom `pipe()`
Type inferencePolymorphic โ€” `'a -> 'b` chain naturalGeneric bounds โ€” more verbose but explicit
Point-free styleNatural โ€” `let h = f \> g`Possible but needs wrapper functions
//! # 509. Composing Functions and Closures
//! Building complex transformations from simple composed pieces.

/// Compose two functions: apply g first, then f
/// compose(f, g)(x) == f(g(x))
fn compose<A, B, C, F, G>(f: F, g: G) -> impl Fn(A) -> C
where
    F: Fn(B) -> C,
    G: Fn(A) -> B,
{
    move |x| f(g(x))
}

/// Pipe: apply f first, then g (left-to-right composition)
fn pipe<A, B, C, F, G>(f: F, g: G) -> impl Fn(A) -> C
where
    F: Fn(A) -> B,
    G: Fn(B) -> C,
{
    move |x| g(f(x))
}

/// Build a pipeline from a Vec of boxed transformations
fn make_pipeline<T>(transforms: Vec<Box<dyn Fn(T) -> T>>) -> impl Fn(T) -> T {
    move |x| transforms.iter().fold(x, |acc, f| f(acc))
}

/// Trait extension for composable transforms
trait Composable<B>: Sized {
    fn then_apply<C, F: Fn(B) -> C>(self, other: F) -> impl Fn(i32) -> C
    where
        Self: Fn(i32) -> B;
}

/// A builder that accumulates transformations
struct Pipeline<T> {
    steps: Vec<Box<dyn Fn(T) -> T>>,
}

impl<T: 'static> Pipeline<T> {
    fn new() -> Self { Pipeline { steps: Vec::new() } }

    fn then(mut self, f: impl Fn(T) -> T + 'static) -> Self {
        self.steps.push(Box::new(f));
        self
    }

    fn run(self) -> impl Fn(T) -> T {
        make_pipeline(self.steps)
    }
}

fn main() {
    let double = |x: i32| x * 2;
    let inc    = |x: i32| x + 1;
    let square = |x: i32| x * x;

    // compose: right-to-left (mathematical notation)
    let double_then_inc = compose(inc, double); // inc(double(x))
    println!("double_then_inc(5) = {}", double_then_inc(5)); // 11

    // pipe: left-to-right (data flow notation)
    let process = pipe(pipe(double, inc), square); // ((x*2)+1)^2
    println!("double|inc|square(3) = {}", process(3)); // 49

    // Manual chain
    let chained = compose(square, compose(inc, double));
    println!("chained(3) = {}", chained(3)); // 49

    // Multi-step pipeline builder
    let pipeline = Pipeline::new()
        .then(|x: i32| x * 2)
        .then(|x| x + 1)
        .then(|x| x * x)
        .then(|x| x - 1)
        .run();
    println!("pipeline(3) = {}", pipeline(3)); // ((3*2)+1)^2 - 1 = 48

    // Compose with different types
    let to_string_len = compose(|s: String| s.len(), |x: i32| x.to_string());
    println!("digits in 12345: {}", to_string_len(12345));

    // Point-free style: compose a chain
    let transforms: Vec<Box<dyn Fn(i32) -> i32>> = vec![
        Box::new(double),
        Box::new(inc),
        Box::new(square),
    ];
    let pipeline2 = make_pipeline(transforms);
    println!("pipeline2(2) = {}", pipeline2(2)); // ((2*2)+1)^2 = 25
}

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

    #[test]
    fn test_compose() {
        let f = compose(|x: i32| x + 1, |x| x * 2);
        assert_eq!(f(5), 11); // (5*2)+1
    }

    #[test]
    fn test_pipe() {
        let f = pipe(|x: i32| x * 2, |x| x + 1);
        assert_eq!(f(5), 11); // (5*2)+1
    }

    #[test]
    fn test_pipeline_builder() {
        let p = Pipeline::new()
            .then(|x: i32| x + 1)
            .then(|x| x * 3)
            .run();
        assert_eq!(p(4), 15); // (4+1)*3
    }

    #[test]
    fn test_identity_compose() {
        let f = compose(|x: i32| x, |x| x);
        assert_eq!(f(42), 42);
    }
}
(* Function composition in OCaml *)

(* compose: (b -> c) -> (a -> b) -> (a -> c) *)
let compose f g x = f (g x)

(* Pipe forward operator *)
let ( |>> ) x f = f x

(* Compose operator: f << g = compose f g *)
let ( << ) f g x = f (g x)
let ( >> ) g f x = f (g x)  (* pipe through: g then f *)

(* Build a processing pipeline from a list of transforms *)
let pipeline transforms x =
  List.fold_left (fun acc f -> f acc) x transforms

let () =
  let double = fun x -> x * 2 in
  let inc = fun x -> x + 1 in
  let square = fun x -> x * x in
  let to_str = string_of_int in

  (* compose: apply right first *)
  let double_then_inc = compose inc double in
  Printf.printf "double_then_inc(5) = %d\n" (double_then_inc 5); (* 11 *)

  (* using operators *)
  let pipeline_fn = double >> inc >> square in
  Printf.printf "double|inc|square(3) = %d\n" (pipeline_fn 3); (* ((3*2)+1)^2=49 *)

  (* pipe forward for readability *)
  let result = 5 |>> double |>> inc |>> square in
  Printf.printf "5 |>> double |>> inc |>> square = %d\n" result;

  (* point-free style *)
  let process = compose to_str (compose square inc) in
  Printf.printf "process(4) = %s\n" (process 4); (* "(4+1)^2" = "25" *)

  (* pipeline from list *)
  let transforms = [double; inc; square; double] in
  Printf.printf "pipeline(2) = %d\n" (pipeline transforms 2)