use std::{convert, fmt::Display, iter::Map, ops::Add};
pub fn apply<F: FnOnce(X) -> Y, X, Y>(f: F, x: X) -> Y {
f(x)
}
pub fn dot<F: FnOnce(Y) -> Z, G: FnOnce(X) -> Y, X, Y, Z>(f: F, g: G) -> impl FnOnce(X) -> Z {
move |x| f(g(x))
}
pub fn map<F: FnMut(X) -> Y, I: IntoIterator<Item = X>, X, Y>(
f: F,
) -> impl FnOnce(I) -> Map<I::IntoIter, F> {
move |xs| xs.into_iter().map(f)
}
pub fn join<I: IntoIterator<Item = T>, T: Display>(sep: &'static str) -> impl FnMut(I) -> String {
move |xs| {
xs.into_iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(sep)
}
}
pub fn matrix<I: IntoIterator<Item = J>, J: IntoIterator<Item = T>, T: Display>(
sep: &'static str,
) -> impl FnMut(I) -> String {
move |xs| join("\n")(map(join(sep))(xs))
}
pub fn add<L: Copy + Add<R, Output = O>, R, O>(lhs: L) -> impl FnMut(R) -> O {
move |rhs| lhs + rhs
}
pub fn yn(yes: &'static str, no: &'static str) -> impl FnMut(bool) -> &'static str {
move |p| if p { yes } else { no }
}
pub fn or<A: Display, B: Display>(or: B) -> impl FnMut(Option<A>) -> String {
move |x| x.map(|x| x.to_string()).unwrap_or_else(|| or.to_string())
}
pub fn tuple<T: DisplayTuple>(sep: &'static str) -> impl FnMut(T) -> String {
move |tuple| tuple.format(sep)
}
pub trait DisplayTuple {
fn format(&self, sep: &str) -> String;
}
macro_rules! impl_display_tuple(($(impl<$($type_param:ident : _),*> _ for $self_ty:ty { $fn:expr };)*) => {
$(
impl<$($type_param: Display),*> DisplayTuple for $self_ty {
fn format(&self, sep: &str) -> String {
convert::identity::<fn(&_, _) -> _>($fn)(self, sep)
}
}
)*
});
impl_display_tuple! {
impl<A: _> _ for (A,) { |(a,) , _ | format!("{}", a) };
impl<A: _, B: _> _ for (A, B) { |(a, b) , sep| format!("{}{}{}", a, sep, b) };
impl<A: _, B: _, C: _> _ for (A, B, C) { |(a, b, c) , sep| format!("{}{}{}{1}{}", a, sep, b, c) };
impl<A: _, B: _, C: _, D: _> _ for (A, B, C, D) { |(a, b, c, d), sep| format!("{}{}{}{1}{}{1}{}", a, sep, b, c, d) };
}