Skip to content

Instantly share code, notes, and snippets.

@ziwon
Last active December 29, 2015 12:48
Show Gist options
  • Save ziwon/7672521 to your computer and use it in GitHub Desktop.
Save ziwon/7672521 to your computer and use it in GitHub Desktop.
A Note on Capturing type constraints with evidence parameters
// 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