Permalink
Browse files

Added infrastructure to enable easy enrichment of GenTraversables.

  • Loading branch information...
milessabin committed Apr 29, 2012
1 parent ce896d6 commit 73f7001d963a80950751b4e13b95b05d2526edc8
@@ -411,3 +411,12 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with
def stringPrefix: String
}
+
+object GenTraversableLike {
+ /** Manufacture a conversion from collection representation type `Repr` to
+ * its corresponding `GenTraversableLike` given an implicitly available
+ * instance of `FromRepr[Repr]`.
+ * @see [[scala.collection.generic.FromRepr]]
+ */
+ implicit def fromRepr[Repr](implicit fr : FromRepr[Repr]) = fr.hasElem
+}
@@ -0,0 +1,56 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2012, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.collection
+package generic
+
+/** Type class witnessing that a collection representation type `Repr` has
+ * elements of type `A` and has a conversion to `GenTraversableLike[A, Repr]`.
+ *
+ * This type enables simple enrichment of `GenTraversable`s with extension
+ * methods which can make full use of the mechanics of the Scala collections
+ * framework in their implementation.
+ *
+ * Example usage,
+ * {{{
+ * import scala.collection.generic.{ CanBuildFrom, FromRepr, HasElem }
+ *
+ * class FilterMapImpl[A, Repr](val r : Repr)(implicit hasElem : HasElem[Repr, A]) {
+ * def filterMap[B, That](f : A => Option[B])
+ * (implicit cbf : CanBuildFrom[Repr, B, That]) : That = r.flatMap(f(_).toSeq)
+ * }
+ *
+ * implicit def filterMap[Repr : FromRepr](r : Repr) = new FilterMapImpl(r)
+ *
+ * val l = List(1, 2, 3, 4, 5)
+ * List(1, 2, 3, 4, 5) filterMap (i => if(i % 2 == 0) Some(i) else None)
+ * // == List(2, 4)
+ * }}}
+ *
+ * @author Miles Sabin
+ * @since 2.10
+ */
+trait FromRepr[Repr] {
+ type A
+ val hasElem: HasElem[Repr, A]
+}
+
+object FromRepr {
+ import language.higherKinds
+
+ implicit val stringFromRepr : FromRepr[String] { type A = Char } = new FromRepr[String] {
+ type A = Char
+ val hasElem = implicitly[HasElem[String, Char]]
+ }
+
+ implicit def genTraversableLikeFromRepr[C[_], A0]
+ (implicit hasElem0: HasElem[C[A0], A0]) : FromRepr[C[A0]] { type A = A0 } = new FromRepr[C[A0]] {
+ type A = A0
+ val hasElem = hasElem0
+ }
+}
@@ -4,6 +4,12 @@ import generic.CanBuildFrom
package object generic {
type CanBuild[-Elem, +To] = CanBuildFrom[Nothing, Elem, To]
+ /** The type of conversions from a collection representation type
+ * `Repr` to its corresponding GenTraversableLike.
+ * @see [[scala.collection.generic.FromRepr]]
+ */
+ type HasElem[Repr, A] = Repr => GenTraversableLike[A, Repr]
+
@deprecated("use ArrayTagTraversableFactory instead", "2.10.0")
type ClassManifestTraversableFactory[CC[X] <: Traversable[X] with GenericClassManifestTraversableTemplate[X, CC]] = ArrayTagTraversableFactory[CC]
@@ -0,0 +1,4 @@
+List(2, 4)
+Array(2, 4)
+HW
+Vector(72, 108, 108, 32, 114, 108, 100)
@@ -0,0 +1,30 @@
+object Test extends App {
+ import scala.collection.generic.{ CanBuildFrom, FromRepr, HasElem }
+
+ def typed[T](t : => T) {}
+
+ class FilterMapImpl[A, Repr](val r : Repr)(implicit hasElem : HasElem[Repr, A]) {
+ def filterMap[B, That](f : A => Option[B])(implicit cbf : CanBuildFrom[Repr, B, That]) : That = r.flatMap(f(_).toSeq)
+ }
+
+ implicit def filterMap[Repr : FromRepr](r : Repr) = new FilterMapImpl(r)
+
+ val l = List(1, 2, 3, 4, 5)
+ val fml = l.filterMap(i => if(i % 2 == 0) Some(i) else None)
+ typed[List[Int]](fml)
+ println(fml)
+
+ val a = Array(1, 2, 3, 4, 5)
+ val fma = a.filterMap(i => if(i % 2 == 0) Some(i) else None)
+ typed[Array[Int]](fma)
+ println(fma.deep)
+
+ val s = "Hello World"
+ val fms1 = s.filterMap(c => if(c >= 'A' && c <= 'Z') Some(c) else None)
+ typed[String](fms1)
+ println(fms1)
+
+ val fms2 = s.filterMap(c =>if(c % 2 == 0) Some(c.toInt) else None)
+ typed[IndexedSeq[Int]](fms2)
+ println(fms2)
+}

0 comments on commit 73f7001

Please sign in to comment.