Last active
December 29, 2015 12:48
-
-
Save ziwon/7672521 to your computer and use it in GitHub Desktop.
A Note on Capturing type constraints with evidence parameters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 7.3.2 Capturing type constraints from Joshua's "Scala in Depth" | |
scala> def pop[A, C <: Seq[A]](col : C) = col.head | |
scala> pop(List(1, 2)) | |
// error: inferred type arguments [Nothing,List[Int]] do not conform to method pop's type parameter bounds [A,C <: Seq[A]] | |
// pop(List(1, 2)) | |
// ^ | |
scala> def pop[C, A](col : C)(implicit ev: C <:< Seq[A]) = col.head | |
scala> pop(List(1, 2)) | |
// res0: Int = 1 | |
/* | |
In first pop() | |
C: List[Int] has successfully inferred while Nothing is inferred instead of Int for A. | |
In second pop() | |
The compiler finds out C: List[Int] from 1st parameter | |
Next, it looks for implicit ev: <:<[List[Int], Seq[A]] with unknown A. | |
For type <:<[List[Int], Seq[A]], there must be an implicit conversion. | |
Because List[Int] is contravariant in Seq[A] and Int is contravariant in A. | |
It allows the compiler to get <:<[Seq[A], Seq[A]] for type <:<[List[Int], Seq[A]]. | |
To summarize, the evidence parameter B <:< A provide an implicit conversion from B to A, | |
it means B must be a subtype of A. | |
*/ | |
// Predef.scala#L378 | |
@implicitNotFound(msg = "Cannot prove that ${From} <:< ${To}.") | |
sealed abstract class <:<[-From, +To] extends (From => To) with Serializable | |
private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x } | |
// not in the <:< companion object because it is also | |
// intended to subsume identity (which is no longer implicit) | |
implicit def conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A] | |
// Simplify the above from Joshua's book | |
sealed abstract class <:<[-From, +To] extends (From => To) with Serializable | |
implicit def conforms[A]: A <:< A = new (A <:< A) { | |
def apply(x: A) = x | |
} | |
// The trick behind: | |
scala> trait <::<[-From, +To] | |
scala> implicit def intList = new <::<[List[Int], List[Int]] {} | |
scala> implicitly[<::<[List[Int], Seq[Int]]] // def implicitly[T](implicit e: T): T = e | |
res0: <::<[List[Int],Seq[Int]] = $anon$1@73f9d297 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment