haskell covariance contravariance

¿Por qué no hay muchas discusiones sobre contra y varianza en Haskell(a diferencia de Scala o C#)?



covariance contravariance (3)

Sé lo que son la covarianza y la contravarianza de los tipos. Mi pregunta es: ¿por qué no me he encontrado con la discusión de estos conceptos todavía en mi estudio de Haskell (en oposición a, digamos, Scala)?

Parece que hay una diferencia fundamental en la forma en que Haskell ve los tipos en oposición a Scala o C #, y me gustaría articular cuál es esa diferencia.

O tal vez estoy equivocado y aún no he aprendido lo suficiente de Haskell :-)


Como se mencionó, Haskell no tiene subtipos. Sin embargo, si está buscando clases de tipos, puede que no quede claro cómo funciona eso sin subtipificación.

Las clases de tipos especifican predicados en tipos, no tipos en sí mismos. Entonces, cuando una clase de tipo tiene una superclase (por ejemplo, Eq a => Ord a), eso no significa que las instancias sean subtipos, porque solo los predicados se heredan, no los tipos en sí mismos.

Además, co, contra y variabilidad significan cosas diferentes en diferentes campos de las matemáticas (ver Wikipedia). Por ejemplo, los términos covariantes y contravariantes se usan en funtores (que a su vez se usan en Haskell), pero los términos significan algo completamente diferente. El término invariante se puede usar en muchos lugares.


Hay dos razones principales:

  • Haskell carece de una noción inherente de subtipado, por lo que en general la varianza es menos relevante.
  • La contravariancia aparece principalmente cuando está involucrada la mutabilidad, por lo que la mayoría de los tipos de datos en Haskell serían simplemente covariantes y habría poco valor para distinguirlos explícitamente.

Sin embargo, los conceptos se aplican, por ejemplo, la operación de elevación realizada por fmap para las instancias de Functor es realmente covariante; los términos co- / contravariancia se usan en la teoría de categorías para hablar de funtores. El paquete contravariant define una clase de tipo para funtores contravariantes, y si miras la lista de instancias verás por qué dije que es mucho menos común.

También hay lugares donde la idea aparece implícitamente, en cómo funcionan las conversiones manuales: las diversas clases de tipos numéricos definen las conversiones Data.List desde tipos básicos como Integer y Rational , y el módulo Data.List contiene versiones genéricas de algunas funciones estándar. Si observa los tipos de estas versiones genéricas , verá que las restricciones Integral (que dan a toInteger ) se usan en tipos en posición contravariante, mientras que las restricciones de Num (que dan desde fromInteger ) se usan para la posición covariante.


No hay "subtipos" en Haskell, por lo que la covarianza y la contravarianza no tienen ningún sentido.

En Scala, tiene, por ejemplo, la Option[+A] con las subclases Some[+A] y None . Debe proporcionar las anotaciones de covarianza + para decir que una Option[Foo] es una Option[Bar] si Foo extends Bar . Debido a la presencia de subtipos, esto es necesario.

En Haskell, no hay subtipos. El equivalente de Option en Haskell, llamado Maybe , tiene esta definición:

data Maybe a = Nothing | Just a

La variable de tipo a solo puede ser un solo tipo, por lo que no es necesario obtener más información al respecto.