Regla general
Estamos llegando a una regla más o menos universal que es: lo que se escribe desde fuera del tipo se hace contravariante, lo que se lee desde fuera del tipo se hace covariante.En una función: Se pasan (escriben) argumentos y se devuelve (lee) el retorno. Las funciones son contravariantes en los argumentos y covariantes en el retorno.
Esto tiene que matizarse y veremos por qué en el siguiente apartado.
Menos por menos es más
Ahora vamos a hacer un esfuerzo mental para pensar en lo que ocurre cuando pasamos una función a otra función.
La función "total_sillas" tiene el siguiente tipo:
total_sillas :: (S -> int) -> int
Esta función conoce de alguna manera todas las sillas de mi casa y usa la función que se le pasa de argumento (la S -> int) para obtener alguna propiedad numérica de estas sillas. Finalmente, retorna la suma total de estos números.
La función "total_muebles" es igual, pero trabaja con los muebles.
total_muebles :: (M -> int) -> int
Como propiedades numéricas vamos a usar estas dos funciones:
cuenta_patas :: S -> int
altura_mueble :: M -> int
Ahora vamos a ver si una se puede usar donde la otra o no.
total_muebles(altura_mueble) // OK, mismo tipo
total_sillas(altura_muebles)//Bien,las sillas tienen altura
total_sillas(cuenta_patas) //OK, mismo tipo
total_muebles(cuenta_patas) //Mal, hay muebles sin patas
Así que puedo usar "total_sillas" donde usaba "total_muebles", es decir:
S <: M
(S -> int) -> int <: (M -> int) -> int
Lo que significa que ¡es covariante! Esto es muy curioso porque los argumentos de una función eran contravariantes, pero los argumentos de los argumentos que serían contra-contravariantes son covariantes.
La moraleja a recordar es: La contravariancia es como el menos en la multiplicación, menos por menos es más. O sea, contravariante de contravariante es covariante.
Esto nos lleva a una regla muy usada en la teoría de tipos que es: Será covariante si está a la izquierda de un número par de "->" y contravariante en caso contrario. Esta regla se puede ver en el capítulo dedicado a la teoría de tipos del manual de las ciencias de la computación escrito por Cardelli. En la página 28.
Escribiré "cov" cuando sea covariante y "con" cuando sea contravariante en estos ejemplos:
con -> con -> cov (Se asocia por la derecha)
(cov -> con) -> cov
con-> (cov -> con) -> cov
(cov -> cov -> con) -> cov
((con -> cov) -> con) ->cov
En la siguiente parte de este serial veremos cómo afecta la mutabilidad a la variancia de tipos mediante el uso de punteros.