4

希望这将是一个关于图书馆拉皮条的简单问题(因为关于该主题的其他问题往往会产生超出我当前技能水平的答案)。

我想要做的就是映射一个集合的叉积与它自己。

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 很陌生)。我还尝试了使用丰富 Scala 集合中建议的方法,该方法给我留下了:

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, _)))
}

,但这会引发与我的(看起来更简单的)方式相同的错误。

我在这里做错了什么?

4

2 回答 2

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)
于 2013-05-06T10:06:51.597 回答
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 的回答涵盖了一些额外的情况,其中集合不是直接 a GenTraversableLike,即Arrayand String(尝试在最后一个示例中替换VectorArray

于 2013-05-06T17:51:31.300 回答