希望这将是一个关于图书馆拉皮条的简单问题(因为关于该主题的其他问题往往会产生超出我目前技能水平的答案)。
我想要做的就是将集合的交叉产品映射到自身。
val distances = points.crossMap(_ distance _) // points: List[Point3d]
所以我试图皮条Traversable
因此:
implicit def toSelfCrossMappable[A](xs: Traversable[A]) = new {
def crossMap[B](f: (A, A) => B) = xs.flatMap(a => xs.map(f(a, _)))
}
但是它不起作用(它没有进行隐式转换)而且我不明白为什么不(我对scala很新)。我也尝试了Enriching Scala collections with a method中建议的方法,它留给我:
implicit def toSelfCrossMappable[A, C[A]](xs: C[A])(implicit c: C[A] => Traversable[A]) = new SelfCrossable[A, C[A]](xs)(c)
class SelfCrossable[A, C](xs: C)(implicit c: C => Traversable[A]) {
def crossMap[B](f: (A, A) => B) = xs.flatMap(a => xs.map(f(a, _)))
}
,但是抛出与我(看起来更简单)方式相同的错误。
我在这里做错了什么?
答案 0 :(得分:10)
它不漂亮,但可以使用IsTraversableLike
,
import scala.language.implicitConversions
import scala.collection.generic.{ CanBuildFrom, IsTraversableLike }
import scala.collection.GenTraversableLike
class SelfCrossMappable[A, Repr](xs: GenTraversableLike[A, Repr]) {
def crossMap[B, That](f: (A, A) => B)
(implicit
cbf: CanBuildFrom[Repr, B, That],
itl: IsTraversableLike[That] { type A = B }
) = xs.flatMap { a => itl.conversion(xs.map(f(a, _)))
}
}
implicit def toSelfCrossMappable[Repr](xs: Repr)
(implicit traversable: IsTraversableLike[Repr]) =
new SelfCrossMappable(traversable.conversion(xs))
示例REPL会话,
scala> List("foo", "foo", "bar").crossMap(_ == _)
res0: List[Boolean] = List(true, true, false, true, true, false, false, false, true)
答案 1 :(得分:2)
在Scala 2.10中,您可以直接使用隐式类(Miles的回答使用IsTraversableLike
助手,这也需要Scala 2.10)。似乎标准集合不需要toSelfCrossMappable
(可怕名称BTW)。以下适用于我:
import collection.generic.{CanBuildFrom, IsTraversableLike}
import collection.GenTraversableLike
implicit class CanCrossMap[A, Repr](xs: GenTraversableLike[A, Repr]) {
def crossMap[B, That](f: (A, A) => B)(
implicit cbf: CanBuildFrom[Repr, B, That],
itl: IsTraversableLike[That] { type A = B }): That =
xs.flatMap { a => itl.conversion(xs.map(f(a, _)))
}
}
另一种选择是完全忽略IsTraversableLike
:
import collection.GenTraversableOnce
implicit class CanCrossMap[A, Repr](xs: GenTraversableLike[A, Repr]) {
def crossMap[B, That <: GenTraversableOnce[B]](f: (A, A) => B)(
implicit cbf: CanBuildFrom[Repr, B, That]): That =
xs.flatMap { a => xs.map(f(a, _))}
}
示例:
Vector((1.0, 2.0), (3.0, 4.0), (5.0, 6.0)).crossMap { case ((ax, ay), (bx, by)) =>
val dx = bx - ax
val dy = by - ay
math.sqrt(dx*dx + dy*dy)
}
Miles答案涵盖了一些额外的案例,其中集合不是直接GenTraversableLike
,即Array
和String
(尝试用Vector
代替Array
在最后一个例子中)。