我正在尝试实现一个函数,该函数可以在具有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实现它,我尝试了一个非常接近于for选项的实现:
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主要是函子/Monad,所以如果您敢的话,可以使用scalaz来实现这个功能。然而,如果你和我一样,不想尝试,下面是基于基普顿·巴罗斯( Kipton )的答案的解决方案:
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。
发布于 2013-04-16 02:51:58
第一个问题是,在Traversable map方法中发生了很多事情。它为返回最特定的集合类型做了一些工作,这就是您需要CanBuildFrom的原因。第二个问题是Option没有实现Traversable接口,因此它的map方法不需要CanBuildFrom。
这是我能得到的最接近的,
import scala.collection.generic.CanBuildFrom
import collection.TraversableLike
trait CanMap[A, M[_]] {
def map[B](l: M[A])(f: A => B)(implicit bf: CanBuildFrom[M[A], B, M[B]]): M[B]
}
object Test {
// ugly hack to work around nonexistent CanBuildFrom for Option
implicit def optionBuilder[A, B]: CanBuildFrom[Option[A], B, Option[B]] = null
implicit def canmapopt[A] = new CanMap[A, Option] {
def map[B](l: Option[A])(f: A => B)(implicit bf: CanBuildFrom[Option[A], B, Option[B]]): Option[B] = l.map(f)
}
implicit def canmaptrav[A, M[_]](implicit ev: M[A] => TraversableLike[A, M[A]]) = new CanMap[A, M] {
def map[B](l: M[A])(f: (A) => B)(implicit bf: CanBuildFrom[M[A], B, M[B]]): M[B] = l.map(f)
}
// example usage
def mapper[A, B, M[_]](l: M[A])(f: A => B)(implicit cm: CanMap[A,M], bf: CanBuildFrom[M[A], B, M[B]]) = {
cm.map(l)(f)
}
mapper(List(1,2,3))(_ + 1) // List(2,3,4)
mapper(Some(2): Option[Int])(_ + 1) // Some(3)
// (cast to Option[Int] is needed to find the canmapopt implicit)
}顺便说一句,隐式转换到TraversableLike使它也适用于数组,
mapper(Array(1,2,3))(_ + 1) // Array(2, 3, 4)发布于 2013-04-16 02:35:17
首先,我尝试了你的两次失败的尝试,但没有得到什么好处。然后,我决定简单地做我自己的CanMap实现。最后我得到了这个:
def canmaptrav[A] = new CanMap[A, Traversable]{
def map[B](l: Traversable[A])(f: A => B): Traversable[B]= l.map(f)
def flatMap[B](l: Traversable[A])(f: A => Traversable[B]): Traversable[B] = l.flatMap(f)
}看上去就像CanMap[_,Option]。假设您要寻找的子类型是用于用例,如下所示:
canmaptrav[Int].map(List(1,2,3,4))(_ + 1) //> res0: Traversable[Int] = List(2, 3, 4, 5)
canmaptrav[Int].map(Vector(1,2,3,4))(_ + 1) //> res1: Traversable[Int] = Vector(2, 3, 4, 5)现在,如果您希望res1和res0类型是具体类型(列表、向量),那么这种方法实际上必须依赖于CanBuildFrom。
顺便说一句,你知道CanMap几乎就是Monad接口,对吗?
发布于 2013-04-16 09:09:22
斯卡拉兹已经包括了这些类型,它们被称为Monad和Functor。一个简短的例子:
// map
def foo[F[_] : Functor](xs: F[Int]) = xs.map(_ + 1)
scala> foo(List(1,2,3))
res2: List[Int] = List(2, 3, 4)
// flatMap
def flatten[M[_] : Monad](xs: M[M[Int]]) = xs.flatMap(identity)
scala> flatten(List(List(1,2,3)))
res3: List[Int] = List(1, 2, 3)编辑
Future的函子实例可以如下所示:
implicit object FutureFunctor extends Functor[Future] {
def map[A,B](fa: Future[A])(f: A => B) = fa.map(f)
}https://stackoverflow.com/questions/16027237
复制相似问题