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
}
}