//! # 503. Closure as Argument
//! Higher-order functions that accept closures as parameters.
/// Apply a closure to a value (static dispatch โ zero cost)
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
f(x)
}
/// Apply a closure twice
fn apply_twice<T, F: Fn(T) -> T>(f: F, x: T) -> T {
f(f(x))
}
/// Filter a slice with a predicate closure
fn my_filter<T, F: Fn(&T) -> bool>(items: &[T], pred: F) -> Vec<&T> {
items.iter().filter(|x| pred(x)).collect()
}
/// Map with index โ passes (index, &item) to closure
fn mapi<T, U, F: Fn(usize, &T) -> U>(items: &[T], f: F) -> Vec<U> {
items.iter().enumerate().map(|(i, x)| f(i, x)).collect()
}
/// Compose two functions: apply g 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))
}
/// Dynamic dispatch version โ accepts &dyn Fn for heterogeneous use
fn apply_dyn(f: &dyn Fn(i32) -> i32, x: i32) -> i32 {
f(x)
}
/// Repeat a side-effecting closure N times with index
fn repeat_with<F: Fn(usize)>(f: F, n: usize) {
(0..n).for_each(f);
}
fn main() {
// Static dispatch
println!("apply double 5 = {}", apply(|x| x * 2, 5));
println!("apply_twice +3 on 10 = {}", apply_twice(|x| x + 3, 10));
// Filter
let nums = [1, 2, 3, 4, 5, 6];
let evens: Vec<_> = my_filter(&nums, |x| *x % 2 == 0);
println!("evens: {:?}", evens);
// Map with index
let words = ["hello", "world", "rust"];
let indexed = mapi(&words, |i, w| format!("{}:{}", i, w));
println!("indexed: {:?}", indexed);
// Composition
let double_then_inc = compose(|x: i32| x + 1, |x| x * 2);
println!("double_then_inc(5) = {}", double_then_inc(5)); // 11
// Dynamic dispatch
let ops: Vec<Box<dyn Fn(i32) -> i32>> = vec![
Box::new(|x| x + 1),
Box::new(|x| x * 2),
Box::new(|x| x - 3),
];
let result = ops.iter().fold(10, |acc, f| apply_dyn(f.as_ref(), acc));
println!("pipeline(10): {}", result); // (10+1)*2-3 = 19
// Repeat with index
print!("squares: ");
repeat_with(|i| print!("{} ", i * i), 5);
println!();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_apply() {
assert_eq!(apply(|x| x * 3, 4), 12);
}
#[test]
fn test_apply_twice() {
assert_eq!(apply_twice(|x| x + 3, 10), 16);
}
#[test]
fn test_my_filter() {
let v = [1, 2, 3, 4, 5];
let odds = my_filter(&v, |x| *x % 2 != 0);
assert_eq!(odds, vec![&1, &3, &5]);
}
#[test]
fn test_mapi() {
let v = [10, 20, 30];
let r = mapi(&v, |i, x| i as i32 * (*x));
assert_eq!(r, vec![0, 20, 60]);
}
#[test]
fn test_compose() {
let f = compose(|x: i32| x + 1, |x| x * 2);
assert_eq!(f(5), 11);
assert_eq!(f(0), 1);
}
}
(* Passing functions/closures as arguments in OCaml *)
(* Basic higher-order function *)
let apply f x = f x
(* Apply a function twice *)
let apply_twice f x = f (f x)
(* Filter a list with a predicate *)
let my_filter pred lst =
List.fold_right (fun x acc -> if pred x then x :: acc else acc) lst []
(* Transform with index *)
let mapi f lst =
let rec go i = function
| [] -> []
| x :: xs -> f i x :: go (i + 1) xs
in
go 0 lst
(* Compose two functions *)
let compose f g x = f (g x)
(* Run a side-effecting function n times with index *)
let repeat_with f n =
for i = 0 to n - 1 do f i done
let () =
Printf.printf "apply double 5 = %d\n" (apply (fun x -> x * 2) 5);
Printf.printf "apply_twice +3 on 10 = %d\n" (apply_twice (fun x -> x + 3) 10);
let evens = my_filter (fun x -> x mod 2 = 0) [1;2;3;4;5;6] in
Printf.printf "evens: [%s]\n" (String.concat ";" (List.map string_of_int evens));
let indexed = mapi (fun i x -> Printf.sprintf "%d:%d" i x) [10;20;30] in
Printf.printf "indexed: [%s]\n" (String.concat ";" indexed);
let double_then_inc = compose (fun x -> x + 1) (fun x -> x * 2) in
Printf.printf "double_then_inc 5 = %d\n" (double_then_inc 5);
print_string "squares: ";
repeat_with (fun i -> Printf.printf "%d " (i * i)) 5;
print_newline ()