Should there by an array::zip method?

You should "just" need closure combinators:

pub trait Transform<T>: FnMut<(T,)> {
    fn map<F: Transform<Self::U>>(self, f: F) -> impl FnMut(T) -> F::Output {
        move |item| f(self(item))
    }
    fn zip<U, F: Transform<U>>(self, f: F) -> impl FnMut((T, U)) -> (Self::Output, F::Output) {
        move |(item, iuem)| (self(item), f(iuem))
    }
}
impl<T, U, F: FnMut(T) -> U> Transform<T> for F {}

pub use core::convert::identity as start_pipe;

trait Apply<T> {
    type Output<U>;
    fn apply<F: Transform<T>>(self, f: F) -> Self::Output<F::Output>;
}

impl<I: Iterator> Apply<I::Item> for I {
    type Output<U> = impl Iterator<Item=U>;
    fn apply<F: Transform<I::Item>>(self, f: F) -> Self::Output<F::Output> {
        self.map(f)
    }
}
impl<I: Iterator, J: Iterator> Apply<(I::Item, J::Item)> for (I, J) {
    type Output<U> = impl Iterator<Item=U>;
    fn apply<F: Transform<(I::Item, J::Item)>>(self, f: F) -> Self::Output<(I::Output, J::Output)> {
        let (i, j) = self;
        i.zip(j).map(f)
    }
}

// etc for other monadish types

(entirely untested)

1 Like