Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you can write generic Scala enhancement methods that bind collection type as well as element type?

If you are like me, you occasionally want to write enhanced methods for Scala collections or sequences, but you'd like to bind the collection type as well as the element type, not just upcast to Seq[T].

like image 536
eje Avatar asked Sep 04 '15 18:09

eje


1 Answers

There is a way to do it, and it works like this:

object enhance {
  import scala.language.higherKinds
  import scala.language.implicitConversions
  import scala.collection.SeqLike
  import scala.collection.generic.CanBuildFrom

  implicit class Enhance[T, S[E] <: SeqLike[E, S[E]]](seq: S[T]) {
    def first3(implicit cbf: CanBuildFrom[S[T], T, S[T]]) = seq.take(3)
    def foo = seq.iterator
    def goo(implicit cbf: CanBuildFrom[Nothing, T, S[T]]) = foo.take(3).to[S]
    def moo[U](f: T => U)(implicit cbf: CanBuildFrom[S[T], U, S[U]]) = seq.map(f)
  }
}

Using the type signature pattern above, the enhanced methods are aware of both the element type T (e.g. Int or String) and the higher-kinded sequence type S (e.g. List or Vector) and so it can return exactly the sequence type that it was called on.

Many sequence methods may require CanBuildFrom implicits, which are added to the Enhance methods as implicit parameters, where they are needed in the examples above.

Following is a sample run, showing the desired higher-kinded collection return types:

scala> import enhance._
import enhance._

scala> (1 to 10).toList.first3
res0: List[Int] = List(1, 2, 3)

scala> (1 to 10).toVector.first3
res1: Vector[Int] = Vector(1, 2, 3)

scala> (1 to 10).toList.goo
res2: List[Int] = List(1, 2, 3)

scala> (1 to 10).toVector.goo
res3: Vector[Int] = Vector(1, 2, 3)

scala> (1 to 10).toList.moo(_.toDouble)
res4: List[Double] = List(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)

scala> (1 to 10).toVector.moo(_.toDouble)
res5: Vector[Double] = Vector(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)
like image 175
eje Avatar answered Sep 30 '22 03:09

eje