diff options
-rw-r--r-- | src/library/scala/collection/GenTraversableLike.scala | 9 | ||||
-rw-r--r-- | src/library/scala/collection/generic/FromRepr.scala | 56 | ||||
-rw-r--r-- | src/library/scala/collection/generic/package.scala | 6 | ||||
-rw-r--r-- | test/files/run/enrich-gentraversable.check | 4 | ||||
-rw-r--r-- | test/files/run/enrich-gentraversable.scala | 30 |
5 files changed, 105 insertions, 0 deletions
diff --git a/src/library/scala/collection/GenTraversableLike.scala b/src/library/scala/collection/GenTraversableLike.scala index 0d51230623..eaec7a2a76 100644 --- a/src/library/scala/collection/GenTraversableLike.scala +++ b/src/library/scala/collection/GenTraversableLike.scala @@ -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 +} diff --git a/src/library/scala/collection/generic/FromRepr.scala b/src/library/scala/collection/generic/FromRepr.scala new file mode 100644 index 0000000000..c08761332c --- /dev/null +++ b/src/library/scala/collection/generic/FromRepr.scala @@ -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 + } +} diff --git a/src/library/scala/collection/generic/package.scala b/src/library/scala/collection/generic/package.scala index 32006b4bf0..e0351ebae6 100644 --- a/src/library/scala/collection/generic/package.scala +++ b/src/library/scala/collection/generic/package.scala @@ -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] diff --git a/test/files/run/enrich-gentraversable.check b/test/files/run/enrich-gentraversable.check new file mode 100644 index 0000000000..348b38d6a4 --- /dev/null +++ b/test/files/run/enrich-gentraversable.check @@ -0,0 +1,4 @@ +List(2, 4) +Array(2, 4) +HW +Vector(72, 108, 108, 32, 114, 108, 100) diff --git a/test/files/run/enrich-gentraversable.scala b/test/files/run/enrich-gentraversable.scala new file mode 100644 index 0000000000..c9320ff985 --- /dev/null +++ b/test/files/run/enrich-gentraversable.scala @@ -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) +} |