use crate::category::Category;
pub trait Arrow: Category {
fn arr<A: Clone + 'static, B: Clone + 'static>(f: impl Fn(A) -> B + 'static) -> Self::P<A, B>;
fn first<A: Clone + 'static, B: Clone + 'static, C: Clone + 'static>(
pab: Self::P<A, B>,
) -> Self::P<(A, C), (B, C)>;
fn second<A: Clone + 'static, B: Clone + 'static, C: Clone + 'static>(
pab: Self::P<A, B>,
) -> Self::P<(C, A), (C, B)> {
let swap_in = Self::arr(|(c, a): (C, A)| (a, c));
let swap_out = Self::arr(|(b, c): (B, C)| (c, b));
Self::compose(swap_out, Self::compose(Self::first(pab), swap_in))
}
fn split<A: Clone + 'static, B: Clone + 'static, C: Clone + 'static, D: Clone + 'static>(
f: Self::P<A, B>,
g: Self::P<C, D>,
) -> Self::P<(A, C), (B, D)> {
Self::compose(Self::second(g), Self::first(f))
}
fn fanout<A: Clone + 'static, B: Clone + 'static, C: Clone + 'static>(
f: Self::P<A, B>,
g: Self::P<A, C>,
) -> Self::P<A, (B, C)> {
let dup = Self::arr(move |a: A| {
let a2 = a.clone();
(a, a2)
});
Self::compose(Self::split(f, g), dup)
}
}