Rust: a small requirement for Iteration to support foldmap

Created on 11 Aug 2020  路  8Comments  路  Source: rust-lang/rust

Hi guys,

I want to make a small requirement for Iteration to support foldmap.

foldmap provides an accumulator for mapping like this:

[v0, v1, v2, v3]

-> [v0, v0+v1, v0+v1+v2, v0+v1+v2+v3]

-> [v0, v0(v0+v1), v0(v0+v1)(v0+v1+v2), v0(v0+v1)*(v0+v1+v2+v3)]

In this way, foldmap can be composed conveniently than map.

fn funny(v: Vec<i32>) -> Vec<i32> {
    v.iter()
        .foldmap(0, |acc, x| acc + x)
                .foldmap(1, |acc, x| acc * x)
        .collect()
}

_Originally posted by @zhibo501 in https://github.com/rust-lang/rust/issues/75367#issuecomment-671466066_

A-iterators C-feature-request T-libs

All 8 comments

Interesting idea. I think it may be possible to implement this in userland, maybe it would be useful to add to itertools?

You can do this with scan, or even just a regular map and captured closure arguments. It's a little more verbose to separate the state update and the item return, but also more flexible.

@bugadani

OK, that's good.

But it's better if the language supports this function natively. :)

@cuviper
Thanks for your reply.
scan only supports to return Option type, and flatten is required.
If we use the regular map, we need to define additional variables to store state, like this:

fn funny(v: Vec<i32>) -> Vec<i32> {
        let mut t1 = 0;
        let mut t2 = 1;
    v.iter()
        .map(|x| {t1 = t1 + x; t1})
        .map(|x| {t2 = t2 * x; t2})
        .collect()
}

The scan function returns Option because you can terminate early with None, just like an implementation of Iterator::next(). When you return Some(value) the next stage of the iterator will get an unwrapped value.

fn funny(v: Vec<i32>) -> Vec<i32> {
    v.iter()
        .scan(0, |acc, x| { *acc += x; Some(*acc) })
        .scan(1, |acc, x| { *acc *= x; Some(*acc) })
        .collect()
}

(The dereferencing *acc is because the closure gets &mut St.)

@cuviper It's great. I'm wrong about scan.
However, scan is meaning of browsing elements, and it maybe terminate during scanning. In an abstract sense, it is different from fold and map.
And the code implementation with foldmap is more concise and graceful. :)

@zhibo501 It is very common for crates to be used to demonstrate a functionality is useful and desired before adding them to rustc itself. There has been a recent push to implement Iterator::join based on it being one of the most popular methods of itertools. It is easier and lower friction there, since new features, even methods, only get added as unstable implementations in rustc. That was not a random suggestion, it was your best bet!

Should this be closed since it should be in userland first?

Was this page helpful?
0 / 5 - 0 ratings