Search code examples
scalacollectionsenrich-my-library

How can I add cross product based methods to scala collections?


hopefully this will be a simple question about library pimping (because other questions on that subject tend to generate answers beyond my current skill level).

All I want to do is map over the cross product of a collection with itself.

val distances = points.crossMap(_ distance _)  // points: List[Point3d]

So I attempted to pimp Traversable thus:

implicit def toSelfCrossMappable[A](xs: Traversable[A]) = new {
  def crossMap[B](f: (A, A) => B) = xs.flatMap(a => xs.map(f(a, _)))
}

But it doesn't work (it's not doing the implicit conversion) and I don't understand why not (I'm pretty new to scala). I also tried the method suggested in Enriching Scala collections with a method which left me with:

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

, but that throws the same error as my (simpler looking) way.

What am I doing wrong here?


Solution

  • It's not pretty, but this can be done with 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))
    

    Sample REPL session,

    scala> List("foo", "foo", "bar").crossMap(_ == _)
    res0: List[Boolean] = List(true, true, false, true, true, false, false, false, true)