【发布时间】:2013-04-08 06:41:57
【问题描述】:
我正在尝试实现一个函数,该函数适用于具有map 和flatMap 方法的类型。我已经为Traversable 做了它,但这不直接包括Future 和Option。所以我决定使用我自己的接口,使用类型类:
trait CanMap[A, M[_]] {
def map[B](l: M[A])(f: A => B): M[B]
def flatMap[B](l: M[A])(f: A => M[B]): M[B]
}
我已经为Option实现了这个:
implicit def canmapopt[A] = new CanMap[A, Option] {
def map[B](l: Option[A])(f: A => B): Option[B] = l.map(f)
def flatMap[B](l: Option[A])(f: A => Option[B]): Option[B] = l.flatMap(f)
}
而且这个效果很好。现在我想为 Traversable 的任何子类型实现它,我尝试了一个非常接近 Option 的实现:
implicit def canmaptrav[A, B, T[B] <: Traversable[B]] = new CanMap[A, T] {
def map[B](l: T[A])(f: A => B): T[B] = l.map(f)
def flatMap[B](l: T[A])(f: A => T[B]): T[B] = l.flatMap(f)
}
但我得到了错误:
type mismatch; found : Traversable[B] required: T[B] Note: implicit method canmaptrav is not applicable here because it comes after the application point and it lacks an explicit result type
对于l.map的返回类型。我不明白为什么l.map(f) 会返回Traversable 而不是特定类型T[B]。所以我试图明确地将正确类型的 CanBuildFrom 放在上下文中:
implicit def canmaptrav[A, B, T[B] <: Traversable[B]](implicit cbf: CanBuildFrom[T[A], B, T[B]]) = new CanMap[A, T] {
def map[B](l: T[A])(f: A => B): T[B] = l.map(f)
def flatMap[B](l: T[A])(f: A => T[B]): T[B] = l.flatMap(f)
}
错误仍然存在。
知道我哪里出错了吗?这可能很明显,但我对我猜的泛型类型签名感到困惑。
更新:解决方案
首先,正如答案所指出的,CanMap 主要是一个 Functor/Monad,所以如果你敢,你可以使用 scalaz 来实现它。但是,如果您像我一样想尝试不使用它,这里是基于 Kipton Barros 的回答的解决方案:
trait CanMap[A, B, M[_]] {
def map(l: M[A])(f: A => B): M[B]
def flatMap(l: M[A])(f: A => M[B]): M[B]
}
implicit def canmapopt[A, B] = new CanMap[A, B, Option] {
def map(l: Option[A])(f: A => B): Option[B] = l.map(f)
def flatMap(l: Option[A])(f: A => Option[B]): Option[B] = l.flatMap(f)
}
implicit def canmaptrav[A, B, M[+_]](implicit bf: CanBuildFrom[M[A], B, M[B]], ev: M[A] => TraversableLike[A, M[A]], eb: M[B] => TraversableLike[B, M[B]]) = new CanMap[A, B, M] {
def map(l: M[A])(f: (A) => B): M[B] = l.map(f)
def flatMap(l: M[A])(f: A => M[B]): M[B] = l.flatMap[B, M[B]] { (a: A) =>
f(a)
}
}
诀窍是使用隐式转换 M[A] => TraversableLike[A, M[A]] 而不是尝试子类型 Traversable。
【问题讨论】:
标签: scala collections typeclass