I have reached this far:
implicit def collectionExtras[A](xs: Iterable[A]) = new {
def zipWith[B, C, That](ys: Iterable[B])(f: (A, B) => C)(implicit cbf: Ca
To be honest I'm not sure how that really works:
implicit def collectionExtras[CC[X] <: Iterable[X], A](xs: CC[A]) = new {
import collection.generic.CanBuildFrom
def zipWith[B, C](ys: Iterable[B])(f: (A, B) => C)
(implicit cbf:CanBuildFrom[Nothing, C, CC[C]]): CC[C] = {
xs.zip(ys).map(f.tupled)(collection.breakOut)
}
}
scala> Vector(2, 2, 2).zipWith(Vector(4, 4, 4))(_ * _)
res1: scala.collection.immutable.Vector[Int] = Vector(8, 8, 8)
I sort of monkey patched this answer from retronym until it worked!
Basically, I want to use the CC[X]
type constructor to indicate that zipWith
should return the collection type of xs
but with C
as the type parameter (CC[C]
). And I want to use breakOut
to get the right result type. I sort of hoped that there was a CanBuildFrom
implicit in scope but then got this error message:
required: scala.collection.generic.CanBuildFrom[Iterable[(A, B)],C,CC[C]]
The trick was then to use Nothing
instead of Iterable[(A, B)]
. I guess that implicit is defined somewhere...
Also, I like to think of your zipWith
as zip
and then map
, so I changed the implementation. Here is with your implementation:
implicit def collectionExtras[CC[X] <: Iterable[X], A](xs: CC[A]) = new {
import collection.generic.CanBuildFrom
def zipWith[B, C](ys: Iterable[B])(f: (A, B) => C)
(implicit cbf:CanBuildFrom[Nothing, C, CC[C]]) : CC[C] = {
val builder = cbf()
val (i, j) = (xs.iterator, ys.iterator)
while(i.hasNext && j.hasNext) {
builder += f(i.next, j.next)
}
builder.result
}
}
Note this article provides some background on the type constructor pattern.