如何在Rust中为FlatMap trait实现基于flat_map的默认flatten方法?
为基于HKT的FlatMap trait实现flatten通用默认方法
我正在开发一个对标Scala Cats库的Rust函数式编程库,采用HKT1 trait模拟高阶类型。尝试为FlatMap trait添加签名为flatten(ffa: F<F<A>>) -> F<A>的方法,希望通过flat_map提供默认实现,但代码编译报错。
核心代码
trait HKT1 { type Unwrapped; type Wrapped<T>; } trait FlatMap: HKT1 + Sized { fn flat_map<B, F>(self, f: F) -> Self::Wrapped<B> where F: FnOnce(Self::Unwrapped) -> Self::Wrapped<B>; // 无法编译 fn flatten<A>(ffa: Self::Wrapped<Self::Wrapped<A>>) -> Self::Wrapped<A> // 如何正确设置泛型约束? where Self::Wrapped<Self::Wrapped<A>>: FlatMap { ffa.flat_map(|x| x) } }
编译错误信息
error[E0308]: mismatched types --> src/main.rs:15:26 | 15 | ffa.flat_map(|x| x) | ^ expected HKT1::Wrapped, found HKT1::Unwrapped | = note: expected associated type `<<Self as HKT1>::Wrapped<<Self as HKT1>::Wrapped<A>> as HKT1>::Wrapped<_>` found associated type `<<Self as HKT1>::Wrapped<<Self as HKT1>::Wrapped<A>> as HKT1>::Unwrapped` error[E0308]: mismatched types --> src/main.rs:15:9 | 6 | trait FlatMap: HKT1 + Sized { | --------------------------- this type parameter ... 11 | fn flatten<A>(ffa: Self::Wrapped<Self::Wrapped<A>>) -> Self::Wrapped<A> | ---------------- expected `<Self as HKT1>::Wrapped<A>` because of return type ... 15 | ffa.flat_map(|x| x) | ^^^^^^^^^^^^^^^^^^^ expected type parameter `Self`, found associated type | = note: expected associated type `<Self as HKT1>::Wrapped<A>` found associated type `<<Self as HKT1>::Wrapped<<Self as HKT1>::Wrapped<A>> as HKT1>::Wrapped<_>` = note: you might be missing a type parameter or trait bound
解决方案
问题出在缺少对嵌套Wrapped类型的关联类型约束:编译器无法推断Self::Wrapped<Self::Wrapped<A>>作为FlatMap实现时,其HKT1::Unwrapped和HKT1::Wrapped<T>与外层类型的对应关系。需要在flatten的where子句中明确这些等价性:
trait HKT1 { type Unwrapped; type Wrapped<T>; } trait FlatMap: HKT1 + Sized { fn flat_map<B, F>(self, f: F) -> Self::Wrapped<B> where F: FnOnce(Self::Unwrapped) -> Self::Wrapped<B>; fn flatten<A>(ffa: Self::Wrapped<Self::Wrapped<A>>) -> Self::Wrapped<A> where // 确保嵌套的Wrapped类型实现FlatMap Self::Wrapped<Self::Wrapped<A>>: FlatMap, // 约束嵌套Wrapped的Unwrapped就是外层的Wrapped<A> <Self::Wrapped<Self::Wrapped<A>> as HKT1>::Unwrapped == Self::Wrapped<A>, // 约束嵌套Wrapped的Wrapped<T>与外层的Wrapped<T>完全一致 for<'a> <Self::Wrapped<Self::Wrapped<A>> as HKT1>::Wrapped<A> == Self::Wrapped<A>, { ffa.flat_map(|x| x) } }
约束说明
<Self::Wrapped<Self::Wrapped<A>> as HKT1>::Unwrapped == Self::Wrapped<A>:保证调用flat_map时,闭包接收的参数x类型是Self::Wrapped<A>,与闭包返回的类型一致。for<'a> <Self::Wrapped<Self::Wrapped<A>> as HKT1>::Wrapped<A> == Self::Wrapped<A>:确保flat_map返回的类型就是flatten需要的Self::Wrapped<A>,解决返回类型不匹配的问题。
这样就能通过flat_map为flatten提供通用的默认实现,无需为每个类型单独编写flatten方法。
内容的提问来源于stack exchange,提问作者Campbell He
相关产品推荐
相关产品推荐

