Functional Patterns
Functional programming utilities for composition and lazy evaluation.
pipe
Thread a value through a sequence of functions:
#![allow(unused)]
fn main() {
use rok_utils::fp::pipe;
let result = pipe(5, vec![
|x| x + 1,
|x| x * 2,
|x| x - 3,
]);
// (5 + 1) * 2 - 3 = 9
assert_eq!(result, 9);
}
compose
Create new functions by composing two functions:
#![allow(unused)]
fn main() {
use rok_utils::fp::compose;
let add_then_double = compose(
|x: i32| x * 2,
|x: i32| x + 1,
);
assert_eq!(add_then_double(5), 12); // (5 + 1) * 2
}
tap
Execute side effects without changing the value:
#![allow(unused)]
fn main() {
use rok_utils::fp::tap;
let mut log = Vec::new();
let result = tap(42, |v| log.push(*v));
assert_eq!(result, 42);
assert_eq!(log, vec![42]);
}
Lazy
Lazily initialized value:
#![allow(unused)]
fn main() {
use rok_utils::fp::Lazy;
let config = Lazy::new(|| {
println!("Initializing...");
"config_value".to_string()
});
println!("Before access");
let value = config.get();
println!("After access: {}", value);
}
memoize
Cache function results:
#![allow(unused)]
fn main() {
use rok_utils::fp::memoize;
let expensive = memoize(|x: i32| {
println!("Computing...");
x * x
});
expensive(5); // Computes
expensive(5); // Uses cached result
expensive(3); // Computes new value
}
retry
Retry failed operations:
#![allow(unused)]
fn main() {
use rok_utils::fp::retry;
let mut attempts = 0;
let result = retry(3, || {
attempts += 1;
if attempts < 2 {
Err("failed")
} else {
Ok("success")
}
});
assert_eq!(result.unwrap(), "success");
assert_eq!(attempts, 2);
}
or_default
Get value from Option or default:
#![allow(unused)]
fn main() {
use rok_utils::fp::or_default;
assert_eq!(or_default(Some(42)), 42);
assert_eq!(or_default(None::<i32>), 0);
}