kitfre/Kinder

Is there a way to custom implement Foldable for a struct with multiple type params?

Closed this issue · 4 comments

I want to implement Foldable for some of my own types, but, as with BTreeMap below, some require more than one type parameter. So as a way of demonstration, I wrapped both TreeSet and TreeMap in a new struct and tried to implement Foldable for each.

The one for TreeSet compiles just fine, but the closest I can get for TreeMap get me the error below.

Any tips and/or workaround?


extern crate kinder;

use std::collections::{BTreeSet,BTreeMap};
use kinder::lift::{Foldable, Monoid, SemiGroup, Higher};


struct BTreeSetSack<K>(BTreeSet<K>);
struct BTreeMapSack<K,V>(BTreeMap<K,V>);

impl<K> Foldable for BTreeSetSack<K> {
    type A = K;
    fn foldr<F>(&self, accum: K, f: F) -> K
        where F: FnMut(K, &K) -> K
    {
        self.0.iter().fold(accum, f)
    }
}

impl<K,V> Foldable for BTreeMapSack<K,V> {
    type A = (K,V);
    fn foldr<F>(&self, accum: (K,V), f: F) -> (K,V)
        where F: FnMut(K, (&K,V)) -> (K,V)
    {
        self.0.iter().fold(accum, f)
    }
}

error[E0276]: the requirement `for<'r> F: std::ops::FnMut<(K, (&'r K, V))>` appears on the impl method but not on the corresponding trait method
  --> src/bin/test.rs:21:5
   |
21 |     fn foldr<F>(&self, accum: (K,V), f: F) -> (K,V)
   |     ^

Or, if I try to express it in terms of Self::A, which also works for Set, but not Map, then:

impl<K,V> Foldable for BTreeMapSack<K,V> {
    type A = (K,V);
    fn foldr<F>(&self, accum: Self::A, f: F) -> Self::A
        where F: FnMut(Self::A, &Self::A) -> Self::A
    {
        self.0.iter().fold(accum, f)
    }
}

error[E0277]: the trait bound `F: std::ops::FnMut<((K, V), (&K, &V))>` is not satisfied
  --> src/bin/test.rs:24:23
   |
24 |         self.0.iter().fold(accum, f)
   |                       ^^^^ trait `F: std::ops::FnMut<((K, V), (&K, &V))>` not satisfied
   |
   = help: consider adding a `where F: std::ops::FnMut<((K, V), (&K, &V))>` bound

Noted, thanks! Generally when folding a map, you fold on either the keys or the values, but not both. So a work around would be to implement A as either the K or the V depending on the context, that being said, I'll play around and see if I can manage a way to get your example to compile, thanks!

No worries, and thanks for the feedback.

There's probably a much more elegant map syntax, but ultimately this is what I wanted to do:

impl<K:Sized+Clone,V:Sized+Clone> Foldable for BTreeMapSack<K,V> {
    type A = (K,V);
    fn foldr<F>(&self, mut accum: Self::A, mut f: F) -> Self::A
        where F: FnMut(Self::A, &Self::A) -> (K,V)
    {
        for x in self.0.iter() {
            accum = f(accum, &(x.0.clone(),x.1.clone()));
        }
        accum
    }
}