itertools icon indicating copy to clipboard operation
itertools copied to clipboard

Feature: `and_then`/`and_then_results`

Open Diggsey opened this issue 7 years ago • 2 comments

Similar to map_results, this combinator would allow the mapping function to return an error. The Item type of the iterator would be any Result<T, E> where E1: Into<E>, E2: Into<E>.

Diggsey avatar Dec 02 '18 12:12 Diggsey

I made a version of and_then using a separate trait before seeing this issue:

impl
trait Iteresult: Iterator {
    type Ok;
    type Err;

    fn and_then<B, F, E>(self, f: F) -> AndThen<Self, F>
    where
        F: FnMut(Self::Ok) -> Result<B, E>,
        Self::Err: From<E>;
}

impl<T, E_, I> Iteresult for I
where
    I: Iterator<Item = Result<T, E_>>,
{
    type Ok = T;
    type Err = E_;

    fn and_then<B, F, E>(self, f: F) -> AndThen<Self, F>
    where
        F: FnMut(Self::Ok) -> Result<B, E>,
        E_: From<Self::Err>,
    {
        AndThen { f, iter: self }
    }
}

struct AndThen<I: ?Sized, F> {
    f: F,
    iter: I,
}

impl<T, E_, I: ?Sized, B, F, E> Iterator for AndThen<I, F>
where
    I: Iterator<Item = Result<T, E_>>,
    F: FnMut(T) -> Result<B, E>,
    E_: From<E>,
{
    type Item = Result<B, E_>;

    fn next(&mut self) -> Option<Result<B, E_>> {
        self.iter
            .next()
            .map(|res| res.and_then(|t| Ok((self.f)(t)?)))
    }
}

CAD97 avatar May 28 '19 03:05 CAD97

And here it is on Itertools:

trait Itertools: Iterator {
    ..

    fn and_then<T1, E1, T2, E2, F>(self, f: F) -> AndThen<Self, F>
    where
        Self: Iterator<Item = Result<T1, E1>> + Sized,
        F: FnMut(T1) -> Result<T2, E2>,
        E1: From<E2>,
    {
        AndThen { f, iter: self }
    }
}

struct AndThen<I, F> {
    f: F,
    iter: I,
}

impl<T1, E1, T2, E2, F, I> Iterator for AndThen<I, F>
where
    I: Iterator<Item = Result<T1, E1>>,
    F: FnMut(T1) -> Result<T2, E2>,
    E1: From<E2>,
{
    type Item = Result<T2, E1>;

    fn next(&mut self) -> Option<Result<T2, E1>> {
        self.iter
            .next()
            .map(|res| res.and_then(|t| Ok((self.f)(t)?)))
    }
}

CAD97 avatar May 28 '19 03:05 CAD97