Compiler (or me) Confused about Fold Parameters

This seems like a straightforward piece of code... I have a vector of tuples (cross_product) that I want to chunk and the insert the union of the two elements in the tuple (they're BitVecs) into HashSets:

cross_product.chunks(cross_product.len() / 5).map(|c| {
    c.iter().fold(HashSet::new, |mut hs, p| {
        let mut t = p.0.clone();

I get the following error from the compiler though:

error[E0599]: no method named `insert` found for type `fn() -> std::collections::HashSet<_> {std::collections::HashSet::<_>::new}` in the current scope
   --> src/
987 |                             hs.insert(t);
    |                                ^^^^^^
    = note: hs is a function, perhaps you wish to call it

Why/how is hs a function? I intend it to simply be the first parameter in the function I'm using with fold, the second p is the pair/tuple from the chunk. What am I missing here? Thanks!

You forgot the parentheses:


The compiler thinks you are referring to the function itself.

Hmm... I was going off an example I saw in the Rayon code, in

        .fold(Vec::new, |mut vec, elem| {

Why does this code just use Vec::new (in my case it's HashSet) without parenthesis? What am I missing here?

That's a method on ParallelIterator (which takes a function), not Iterator (which takes a value.)

If I'm correct (it's a big if) Rayon's fold needs multiple init (HashSet in your case).
fold takes a Fn(T, Self::Item) -> T + Sync + Send this way it can generate as many as it needs.
There is also fold_with that takes a value like std::iter::Iterator::fold but for Rayon the value has to be clonable.
@cuviper will be far more capable than I am to explain this.

Yeah, that's right -- rayon has to fold in multiple threads simultaneously, so it takes either a closure with fold or a clonable value with fold_with to allow multiple accumulators. This also means that these folds produce yet another parallel iterator type, which you probably want to reduce for a final result.

1 Like