// Example 077: Generic Bounds
// OCaml type constraints โ Rust <T: Trait> bounds
use std::fmt::Display;
// === Approach 1: Single trait bound ===
fn find_max<T: PartialOrd>(slice: &[T]) -> Option<&T> {
slice.iter().reduce(|a, b| if a >= b { a } else { b })
}
fn find_min<T: PartialOrd>(slice: &[T]) -> Option<&T> {
slice.iter().reduce(|a, b| if a <= b { a } else { b })
}
// === Approach 2: Multiple trait bounds ===
fn print_max<T: PartialOrd + Display>(slice: &[T]) -> Option<String> {
find_max(slice).map(|v| format!("Max: {}", v))
}
fn clamp<T: PartialOrd>(value: T, lo: T, hi: T) -> T {
if value < lo {
lo
} else if value > hi {
hi
} else {
value
}
}
// === Approach 3: Custom trait with bounds ===
trait Summarize: Display {
fn summary(&self) -> String;
}
struct Stats {
name: String,
value: f64,
}
impl Display for Stats {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}={:.2}", self.name, self.value)
}
}
impl Summarize for Stats {
fn summary(&self) -> String {
format!("[{}]", self)
}
}
fn print_summaries<T: Summarize>(items: &[T]) -> String {
items.iter().map(|i| i.summary()).collect::<Vec<_>>().join(", ")
}
// Generic pair operations with bounds
fn pair_map<T, U, F: Fn(T) -> U>(pair: (T, T), f: F) -> (U, U) {
(f(pair.0), f(pair.1))
}
fn pair_fold<T, A, F: Fn(A, T) -> A>(init: A, pair: (T, T), f: F) -> A {
let acc = f(init, pair.0);
f(acc, pair.1)
}
fn main() {
let nums = vec![3, 1, 4, 1, 5, 9, 2, 6];
println!("Max: {:?}", find_max(&nums));
println!("Min: {:?}", find_min(&nums));
println!("{}", print_max(&nums).unwrap());
println!("clamp(15, 0, 10) = {}", clamp(15, 0, 10));
println!("clamp(-5, 0, 10) = {}", clamp(-5, 0, 10));
let stats = vec![
Stats { name: "temp".into(), value: 23.5 },
Stats { name: "humidity".into(), value: 67.0 },
];
println!("Summaries: {}", print_summaries(&stats));
let doubled = pair_map((3, 4), |x| x * 2);
println!("pair_map: {:?}", doubled);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_find_max() {
assert_eq!(find_max(&[3, 1, 4, 1, 5, 9]), Some(&9));
assert_eq!(find_max::<i32>(&[]), None);
assert_eq!(find_max(&[42]), Some(&42));
}
#[test]
fn test_find_min() {
assert_eq!(find_min(&[3, 1, 4, 1, 5, 9]), Some(&1));
assert_eq!(find_min::<i32>(&[]), None);
}
#[test]
fn test_clamp() {
assert_eq!(clamp(15, 0, 10), 10);
assert_eq!(clamp(-5, 0, 10), 0);
assert_eq!(clamp(5, 0, 10), 5);
assert_eq!(clamp(1.5, 0.0, 1.0), 1.0);
}
#[test]
fn test_print_max() {
assert_eq!(print_max(&[1, 2, 3]), Some("Max: 3".to_string()));
assert_eq!(print_max::<i32>(&[]), None);
}
#[test]
fn test_pair_map() {
assert_eq!(pair_map((3, 4), |x| x * 2), (6, 8));
assert_eq!(pair_map((1.0, 2.0), |x: f64| x.sqrt()), (1.0, std::f64::consts::SQRT_2));
}
#[test]
fn test_pair_fold() {
assert_eq!(pair_fold(0, (3, 4), |acc, x| acc + x), 7);
}
#[test]
fn test_summarize() {
let s = Stats { name: "x".into(), value: 1.0 };
assert_eq!(s.summary(), "[x=1.00]");
}
}
(* Example 077: Generic Bounds *)
(* OCaml type constraints โ Rust <T: Trait> bounds *)
(* Approach 1: Polymorphic functions with module constraints *)
module type Printable = sig
type t
val to_string : t -> string
end
module type Comparable = sig
type t
val compare : t -> t -> int
end
(* Approach 2: Using built-in polymorphic compare *)
let find_max lst =
match lst with
| [] -> None
| [x] -> Some x
| x :: rest -> Some (List.fold_left max x rest)
let find_min lst =
match lst with
| [] -> None
| x :: rest -> Some (List.fold_left min x rest)
(* Approach 3: Explicit comparison function parameter *)
let find_max_by (cmp : 'a -> 'a -> int) = function
| [] -> None
| x :: rest ->
Some (List.fold_left (fun acc y -> if cmp acc y >= 0 then acc else y) x rest)
let clamp ~lo ~hi x =
if x < lo then lo
else if x > hi then hi
else x
(* Generic pair operations *)
let pair_map f (a, b) = (f a, f b)
let pair_fold f init (a, b) = f (f init a) b
(* Tests *)
let () =
assert (find_max [3; 1; 4; 1; 5; 9] = Some 9);
assert (find_max [] = None);
assert (find_min [3; 1; 4; 1; 5; 9] = Some 1);
assert (find_max_by compare [3; 1; 4; 1; 5; 9] = Some 9);
assert (find_max_by (fun a b -> compare b a) [3; 1; 4; 1; 5; 9] = Some 1);
assert (clamp ~lo:0 ~hi:10 15 = 10);
assert (clamp ~lo:0 ~hi:10 (-5) = 0);
assert (clamp ~lo:0 ~hi:10 5 = 5);
assert (pair_map (fun x -> x * 2) (3, 4) = (6, 8));
assert (pair_fold (+) 0 (3, 4) = 7);
Printf.printf "โ All tests passed\n"