Skip to content

Commit 25d1f6d

Browse files
committed
Merge pull request scala#563 from milessabin/feature/enrich-gentraversables
Added infrastructure to enable easy enrichment of GenTraversables.
2 parents 8ce8690 + 73f7001 commit 25d1f6d

File tree

5 files changed

+105
-0
lines changed

5 files changed

+105
-0
lines changed

src/library/scala/collection/GenTraversableLike.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,3 +411,12 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with
411411
def stringPrefix: String
412412

413413
}
414+
415+
object GenTraversableLike {
416+
/** Manufacture a conversion from collection representation type `Repr` to
417+
* its corresponding `GenTraversableLike` given an implicitly available
418+
* instance of `FromRepr[Repr]`.
419+
* @see [[scala.collection.generic.FromRepr]]
420+
*/
421+
implicit def fromRepr[Repr](implicit fr : FromRepr[Repr]) = fr.hasElem
422+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* __ *\
2+
** ________ ___ / / ___ Scala API **
3+
** / __/ __// _ | / / / _ | (c) 2003-2012, LAMP/EPFL **
4+
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
5+
** /____/\___/_/ |_/____/_/ | | **
6+
** |/ **
7+
\* */
8+
9+
package scala.collection
10+
package generic
11+
12+
/** Type class witnessing that a collection representation type `Repr` has
13+
* elements of type `A` and has a conversion to `GenTraversableLike[A, Repr]`.
14+
*
15+
* This type enables simple enrichment of `GenTraversable`s with extension
16+
* methods which can make full use of the mechanics of the Scala collections
17+
* framework in their implementation.
18+
*
19+
* Example usage,
20+
* {{{
21+
* import scala.collection.generic.{ CanBuildFrom, FromRepr, HasElem }
22+
*
23+
* class FilterMapImpl[A, Repr](val r : Repr)(implicit hasElem : HasElem[Repr, A]) {
24+
* def filterMap[B, That](f : A => Option[B])
25+
* (implicit cbf : CanBuildFrom[Repr, B, That]) : That = r.flatMap(f(_).toSeq)
26+
* }
27+
*
28+
* implicit def filterMap[Repr : FromRepr](r : Repr) = new FilterMapImpl(r)
29+
*
30+
* val l = List(1, 2, 3, 4, 5)
31+
* List(1, 2, 3, 4, 5) filterMap (i => if(i % 2 == 0) Some(i) else None)
32+
* // == List(2, 4)
33+
* }}}
34+
*
35+
* @author Miles Sabin
36+
* @since 2.10
37+
*/
38+
trait FromRepr[Repr] {
39+
type A
40+
val hasElem: HasElem[Repr, A]
41+
}
42+
43+
object FromRepr {
44+
import language.higherKinds
45+
46+
implicit val stringFromRepr : FromRepr[String] { type A = Char } = new FromRepr[String] {
47+
type A = Char
48+
val hasElem = implicitly[HasElem[String, Char]]
49+
}
50+
51+
implicit def genTraversableLikeFromRepr[C[_], A0]
52+
(implicit hasElem0: HasElem[C[A0], A0]) : FromRepr[C[A0]] { type A = A0 } = new FromRepr[C[A0]] {
53+
type A = A0
54+
val hasElem = hasElem0
55+
}
56+
}

src/library/scala/collection/generic/package.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import generic.CanBuildFrom
44
package object generic {
55
type CanBuild[-Elem, +To] = CanBuildFrom[Nothing, Elem, To]
66

7+
/** The type of conversions from a collection representation type
8+
* `Repr` to its corresponding GenTraversableLike.
9+
* @see [[scala.collection.generic.FromRepr]]
10+
*/
11+
type HasElem[Repr, A] = Repr => GenTraversableLike[A, Repr]
12+
713
@deprecated("use ArrayTagTraversableFactory instead", "2.10.0")
814
type ClassManifestTraversableFactory[CC[X] <: Traversable[X] with GenericClassManifestTraversableTemplate[X, CC]] = ArrayTagTraversableFactory[CC]
915

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
List(2, 4)
2+
Array(2, 4)
3+
HW
4+
Vector(72, 108, 108, 32, 114, 108, 100)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
object Test extends App {
2+
import scala.collection.generic.{ CanBuildFrom, FromRepr, HasElem }
3+
4+
def typed[T](t : => T) {}
5+
6+
class FilterMapImpl[A, Repr](val r : Repr)(implicit hasElem : HasElem[Repr, A]) {
7+
def filterMap[B, That](f : A => Option[B])(implicit cbf : CanBuildFrom[Repr, B, That]) : That = r.flatMap(f(_).toSeq)
8+
}
9+
10+
implicit def filterMap[Repr : FromRepr](r : Repr) = new FilterMapImpl(r)
11+
12+
val l = List(1, 2, 3, 4, 5)
13+
val fml = l.filterMap(i => if(i % 2 == 0) Some(i) else None)
14+
typed[List[Int]](fml)
15+
println(fml)
16+
17+
val a = Array(1, 2, 3, 4, 5)
18+
val fma = a.filterMap(i => if(i % 2 == 0) Some(i) else None)
19+
typed[Array[Int]](fma)
20+
println(fma.deep)
21+
22+
val s = "Hello World"
23+
val fms1 = s.filterMap(c => if(c >= 'A' && c <= 'Z') Some(c) else None)
24+
typed[String](fms1)
25+
println(fms1)
26+
27+
val fms2 = s.filterMap(c =>if(c % 2 == 0) Some(c.toInt) else None)
28+
typed[IndexedSeq[Int]](fms2)
29+
println(fms2)
30+
}

0 commit comments

Comments
 (0)