迭代连续折叠结果的惯用和功能方法是什么?

时间:2017-12-24 11:55:59

标签: functional-programming rust fold

我有一个序列(list,iterator)a0, a1, a2, ...,我使用函数f进行折叠。我想有一台发电机给我

a0, f(a0, a1), f(f(a0, a1), a2), ...

这类似于Mathematica中的FoldList。是否有fold_list功能可用?我找不到任何。

1 个答案:

答案 0 :(得分:2)

我会说最接近的抽象是Iterator::scan。它有点强大,因为它有一个内部可变状态(即可以为得到的迭代器产生不同的值)并且可以提前中止。

您可以像这样使用它来构建迭代器扩展特征:

Playground

pub trait FoldListExt: Iterator {
    fn fold_list<'a, St: 'a, F: 'a>(self, initial_state: St, f: F) -> Box<Iterator<Item = St> + 'a>
    where
        St: Clone,
        F: FnMut(St, Self::Item) -> St,
        Self: 'a;
}

impl<I: Iterator> FoldListExt for I {
    fn fold_list<'a, St: 'a, F: 'a>(
        self,
        initial_state: St,
        mut f: F,
    ) -> Box<Iterator<Item = St> + 'a>
    where
        St: Clone,
        F: FnMut(St, Self::Item) -> St,
        Self: 'a,
    {
        Box::new(self.scan(Some(initial_state), move |state, item| {
            let old_state = state.take().unwrap();
            *state = Some(f(old_state.clone(), item));
            Some(old_state)
        }))
    }
}

pub fn main() {
    println!(
        "{:?}",
        (0..16)
            .into_iter()
            .fold_list(0, |a, b| a + b)
            .collect::<Vec<_>>()
    );
}

我使用Option<St>作为内部可变状态以避免另一个clone()调用。

你可以改用它:

Box::new(self.scan(initial_state, move |state, item| {
    let old_state = state.clone();
    *state = f(old_state.clone(), item);
    Some(old_state)
}))