En mi opinión, los dos ejemplos más simples después de Function
están ordenando y la igualdad. Sin embargo, el primero no es contravariante en la biblioteca estándar de Scala, y el segundo ni siquiera existe en él. Entonces, voy a usar los equivalentes de Scalaz: Order y Equal.
A continuación, necesito una jerarquía de clases, preferiblemente una que sea familiar y, por supuesto, los dos conceptos anteriores deben tener sentido para ella. Si Scala tenía una superclase Number
de todos los tipos numéricos, eso hubiera sido perfecto. Desafortunadamente, no tiene tal cosa.
Así que voy a intentar hacer los ejemplos con colecciones. Para hacerlo simple, consideremos Seq[Int]
y List[Int]
. Debe quedar claro que List[Int]
es un subtipo de Seq[Int]
, es decir, List[Int] <: Seq[Int]
.
Entonces, ¿qué podemos hacer con él? En primer lugar, vamos a escribir algo que compara dos listas:
def smaller(a: List[Int], b: List[Int])(implicit ord: Order[List[Int]]) =
if (ord.order(a,b) == LT) a else b
Ahora voy a escribir un implícito Order
para Seq[Int]
:
implicit val seqOrder = new Order[Seq[Int]] {
def order(a: Seq[Int], b: Seq[Int]) =
if (a.size < b.size) LT
else if (b.size < a.size) GT
else EQ
}
Con estas definiciones, ahora puedo hacer algo como esto:
scala> smaller(List(1), List(1, 2, 3))
res0: List[Int] = List(1)
Nota que estoy pidiendo una Order[List[Int]]
, pero estoy pasando un Order[Seq[Int]]
. Esto significa que Order[Seq[Int]] <: Order[List[Int]]
. Dado que Seq[Int] >: List[Int]
, esto solo es posible debido a contra-varianza.
La siguiente pregunta es: ¿tiene algún sentido?
Consideremos smaller
nuevamente. Quiero comparar dos listas de enteros. Naturalmente, cualquier cosa que compare dos listas es aceptable, pero ¿cuál es la lógica de algo que compara dos Seq[Int]
siendo aceptable?
en la definición de seqOrder
cómo se comparan los elementos parámetros a él. Obviamente, un List[Int]
puede ser un parámetro para algo esperando un Seq[Int]
. De esto se sigue que algo que algo que se compara Seq[Int]
es aceptable en lugar de algo que se puede comparar con List[Int]
: ambos se pueden usar con los mismos parámetros.
¿Qué pasa al revés? Supongamos que tengo un método que solo comparó ::
(contras de la lista), que, junto con Nil
, es un subtipo de List
. Obviamente no pude usar esto, porque smaller
bien podría recibir un Nil
para comparar. Se deduce que no se puede usar Order[::[Int]]
en lugar de Order[List[Int]]
.
Vamos a proceder a la igualdad, y escribir un método para ello:
def equalLists(a: List[Int], b: List[Int])(implicit eq: Equal[List[Int]]) = eq.equal(a, b)
Debido Order
extiende Equal
, lo puedo usar con el mismo implícita arriba:
scala> equalLists(List(4, 5, 6), List(1, 2, 3)) // we are comparing lengths!
res3: Boolean = true
La lógica aquí es el el mismo. Cualquier cosa que pueda decir si dos Seq[Int]
son lo mismo puede, obviamente, también decir si dos List[Int]
son iguales. De eso, se deduce que Equal[Seq[Int]] <: Equal[List[Int]]
, que es verdadero porque Equal
es contravariante.
Vea la respuesta de Daniel Spiewak a http: // stackoverflow.com/questions/663254/scala-covariance-contravariance-question – sourcedelica
... porque nadie usa funciones en el mundo real? =) –