///| Extensional equality for function.
pub fn[A, B : Eq] ext_equal(f : (A) -> B, g : (A) -> B) -> (A) -> Bool {
fn { x => f(x) == g(x) }
}
///| Idempotent function.
pub fn[A : Eq] idempotent(f : (A) -> A) -> (A) -> Bool {
fn { x => f(f(x)) == f(x) }
}
///| Involutory function.
pub fn[A : Eq] involutory(f : (A) -> A) -> (A) -> Bool {
fn { x => f(f(x)) == x }
}
///| Inverse function.
pub fn[A : Eq, B] inverse(f : (A) -> B, g : (B) -> A) -> (A) -> Bool {
fn { x => g(f(x)) == x }
}
///| Monotonic increasing function.
pub fn[A : Compare, B : Compare] mono_increase(
f : (A) -> B
) -> ((A, A)) -> Bool {
fn { (x, y) => x <= y && f(x) <= f(y) }
}
///| Monotonic decreasing function.
pub fn[A : Compare, B : Compare] mono_decrease(
f : (A) -> B
) -> ((A, A)) -> Bool {
fn { (x, y) => x <= y && f(x) >= f(y) }
}
///| Commutative binary operation.
pub fn[A, B : Eq] commutative(f : (A, A) -> B) -> ((A, A)) -> Bool {
fn { (x, y) => f(x, y) == f(y, x) }
}
///| Associative binary operation.
pub fn[A : Eq] associative(f : (A, A) -> A) -> ((A, A, A)) -> Bool {
fn { (x, y, z) => f(f(x, y), z) == f(x, f(y, z)) }
}
///| Distributive binary operation over left
pub fn[A : Eq] distributive_left(
f : (A, A) -> A,
g : (A, A) -> A
) -> ((A, A, A)) -> Bool {
fn { (x, y, z) => f(x, g(y, z)) == g(f(x, y), f(x, z)) }
}
///| Distributive binary operation over right
pub fn[A : Eq] distributive_right(
f : (A, A) -> A,
g : (A, A) -> A
) -> ((A, A, A)) -> Bool {
fn { (x, y, z) => f(g(x, y), z) == g(f(x, z), f(y, z)) }
}