use deep_causality_haft::{HKT2Unbound, NoConstraint, Profunctor};
fn main() {
println!("=== DeepCausality HKT: Profunctor Pattern ===\n");
println!("--- Search Filter Adapter ---");
let string_filter = Function(Box::new(|s: String| s.contains("Pro")));
println!(
"Filter 'Pro': {}",
(string_filter.0)("Professional".to_string())
);
let products = vec![
Product {
id: 1,
name: "Pro Laptop".to_string(),
category: "Electronics".to_string(),
price: 1200.0,
},
Product {
id: 2,
name: "Basic Mouse".to_string(),
category: "Electronics".to_string(),
price: 20.0,
},
];
let product_to_name = |p: Product| p.name;
let product_filter = FunctionWitness::dimap(
string_filter,
product_to_name,
|b| b, );
println!("\nFiltering Products:");
for p in products {
let is_match = (product_filter.0)(p.clone());
println!(
"- {}: {}",
p.name,
if is_match { "MATCH" } else { "NO MATCH" }
);
}
println!("\n--- Price Filter Adapter ---");
let expensive_filter = Function(Box::new(|price: f64| price > 100.0));
let product_to_price = |p: Product| p.price;
let expensive_product_filter = FunctionWitness::dimap(
expensive_filter,
product_to_price,
|b| !b, );
println!("Finding Cheap Products (< 100.0):");
let cheap_product = Product {
id: 3,
name: "Cheap Cable".to_string(),
category: "Accessories".to_string(),
price: 15.0,
};
let is_cheap = (expensive_product_filter.0)(cheap_product.clone());
println!(
"- {}: {}",
cheap_product.name,
if is_cheap { "YES" } else { "NO" }
);
assert!(is_cheap);
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
struct Product {
id: u32,
name: String,
category: String,
price: f64,
}
struct Function<I, O>(Box<dyn Fn(I) -> O>);
struct FunctionWitness;
impl HKT2Unbound for FunctionWitness {
type Constraint = NoConstraint;
type Type<A, B> = Function<A, B>;
}
impl Profunctor<FunctionWitness> for FunctionWitness {
fn dimap<A, B, C, D, F1, F2>(pab: Function<A, B>, f_pre: F1, f_post: F2) -> Function<C, D>
where
F1: FnMut(C) -> A + 'static,
F2: FnMut(B) -> D + 'static,
A: 'static,
B: 'static,
C: 'static,
D: 'static,
{
let inner = pab.0;
let f_pre = std::cell::RefCell::new(f_pre);
let f_post = std::cell::RefCell::new(f_post);
Function(Box::new(move |c| {
let a = (f_pre.borrow_mut())(c);
let b = inner(a);
(f_post.borrow_mut())(b)
}))
}
}