问题和我的目标
我的目标是让this (playground)编译。下面是代码的核心。这是尝试实现所有F<F<A>>
的FlatMap
,如Option<Option<i32>>
。
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>;
// Below cannot compile
fn flatten<A>(ffa: Self::Wrapped<Self::Wrapped<A>>) -> Self::Wrapped<A>
// How to set generic bound correctly?
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
HKT1
是一种模拟F<_>
的方法,允许所有基于它的traits分别访问F
和_
,我从this blog学到了这一点。
我想要做的
我正在尝试构建一个函数式编程箱,它可以将Scala lib cats转换为Rust.(当前的工作是here)。为了实现更高级的类型,我遵循this blog并定义HKT1
trait。它非常优雅,直到我想实现flatten(ffa: F<F<A>>) -> F<A>
,但无法弄清楚如何正确设置泛型边界。
如果我在trait中将其留空,似乎很容易实现。例如:
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>;
}
struct MyF<T>(pub T);
impl<A> HKT1 for MyF<A> {
type Unwrapped = A;
type Wrapped<T> = MyF<T>;
}
impl<T> FlatMap for MyF<T> {
fn flat_map<B, F>(self, f: F) -> MyF<B>
where
F: FnOnce(Self::Unwrapped) -> MyF<B>,
{
f(self.0)
}
fn flatten<A>(ffa: MyF<MyF<A>>) -> MyF<A> {
ffa.flat_map(|x| x)
}
}
但是我希望通过flat_map
有一个默认的实现,我该如何实现呢?
1条答案
按热度按时间vuktfyat1#
通过
EqT
的解决方案我刚刚从the implementation of crate functional中学习了如何实现这个功能。(好吧,实现与上面的有点不同)
关键思想是添加一个trait
EqT
,其目的是Assert两个类型是相等的。这样我们就可以轻松地实现和使用
flatten
: