Это потому, что этот тип свидетеля также является функцией. Он объявлен в Predef
как:
sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
Так A <:< JsValue
также функция (A) => JsValue
. Вы можете задаться вопросом, что делает функция: она ничего не делает, она принимает A
и напрямую возвращает ее (как JsValue
).
Чтобы понять, почему это полезно рассмотреть этот пример:
sealed trait Root { def bip() { println("bip") } }
def makeBip[A <: Root](a: A) {
a.bip() // works because a is known to the type system to be a Root
}
def makeBip2[A](a: A)(implicit ev: A <:< Root) {
a.bip() // works, because implicit resolution turns it into `ev(a).bip()`
}
Последний метод makeBip2
не будет компилироваться без неявное, потому что даже если вы знаете, что a
является Root
благодаря свидетельствам, типа системы нет. Вы могли бы его бросить, это было бы обязательно:
def makeBip3[A](a: A)(implicit ev: A <:< Root) {
a.asInstanceOf[Root].bip() // ugly
}
Но это не так. Если бы у вас был способ, который вы конвертируете a
в Root
... но подождите, вы это сделаете: сами доказательства!
def makeBip4[A](a: A)(implicit ev: A <:< Root) {
ev(a).bip() // works!
}
И поскольку неявные параметры доступны как implicits в рамках метода, a.bip()
будут автоматически преобразованы в ev(a).bip()
и вы никогда не должны знать, функция была вовлечена.
Однако система типа использует только неявный для разрешения A
в JsValue
, но не Seq[A]
в Seq[JsValue]
или ее Reads[A]
в Reads[JsValue]
.
Так в вас случае, this.map(witness)
просто делает систему типа понимают, что Reads[A]
является Reads[JsValue]
, применяя эту функцию, которая ничего не делает, так что он может быть составлен с чем-то, что принимает JsValue
и возвращает B
.
См. Вопрос Generalized type constraits на SO для получения дополнительной информации.