2012-02-15 8 views
52

So cosa sono la covarianza e la contravarianza dei tipi. La mia domanda è: perché non ho ancora avuto occasione di discutere di questi concetti nel mio studio su Haskell (al contrario di, ad esempio, Scala)?Perché non ci sono molte discussioni sulla co- e contro-varianza in Haskell (al contrario di Scala o C#)?

Sembra che ci sia una differenza fondamentale nel modo in cui Haskell visualizza i tipi rispetto a Scala o C#, e mi piacerebbe esprimere la differenza.

O forse mi sbaglio e io non ho imparato abbastanza Haskell ancora :-)

+2

È passato un po 'di tempo ma mi sembra di ricordare qualche finestra di dialogo funzionale/haskellish in questo video sulla co/contra-varianza: http://channel9.msdn.com/shows/Going+Deep/E2E-Brian-Beckman-and -Erik-Meijer-CoContravariance-in-Physics-and-Programming-2-of-2/ – steamer25

risposta

58

ci sono due ragioni principali:

  • Haskell manca una nozione inerente subtyping, così in generale la varianza è meno rilevante.
  • La controvarianza appare principalmente laddove è coinvolta la mutevolezza, quindi la maggior parte dei tipi di dati in Haskell sarebbe semplicemente covariante e non ci sarebbe molto valore per distinguerlo esplicitamente.

Tuttavia, i concetti si applicano - per esempio, l'operazione di sollevamento eseguita da fmap per Functor casi è effettivamente covariante; i termini co/contravarianza sono usati nella teoria delle categorie per parlare dei funtori. Il contravariant package definisce una classe di tipi per i funtori controvarianti e, se si guarda l'elenco delle istanze, si vedrà perché ho detto che è molto meno comune.

Ci sono anche luoghi in cui l'idea si presenta implicitamente, nel modo in cui le conversioni lavoro manuale - le varie classi di tipo numerico definiscono conversioni da e per tipi di base come Integer e Rational, e il modulo Data.List contiene le versioni generiche di alcuni funzioni standard . Se guardi allo the types of these generic versions vedrai che i vincoli Integral (che danno toInteger) sono usati sui tipi in posizione contraria alle posizioni, mentre i vincoli Num (che danno fromInteger) sono usati per la posizione covariante.

+7

Non vedo alcuna relazione tra controvarianza e mutabilità. In effetti, la mutabilità porta all'invarianza. Esempi di controvarianza sono le funzioni input, 'Ord' e' Eq' (i loro equivalenti, ovviamente), nessuno dei quali ha anche dati da modificare. –

+13

@ DanielC.Sobral: la scrittura su un riferimento mutabile è controvariante, essendo un caso speciale di input di funzione. Quindi, mentre i tipi di dati semplici spesso consentono la covarianza, i tipi che consentono la contravarianza tendono a rappresentare sink o output, che sono probabilmente banali a meno che non siano coinvolti alcuni effetti collaterali. Tuttavia, un riferimento mutabile con operazioni di lettura e scrittura è necessariamente invariante. –

+0

@Daniel La controvarianza relativa alla mutabilità può essere vista nella [con funzione] (http://hackage.haskell.org/packages/archive/snap/0.7/doc/html/Snap-Snaplet.html#v:with) fornita dall'API Snaplet di Snap Framework. È stato progettato proprio per consentire alle gerarchie dello stato "mutabile" di essere facilmente manipolato. – mightybyte

21

Non ci sono "sottotipi" in Haskell, quindi la covarianza e la contravarianza non hanno alcun senso.

In Scala, ad es. Option[+A] con le sottoclassi Some[+A] e None. Devi fornire le annotazioni di covarianza + per dire che uno Option[Foo] è un Option[Bar] se Foo extends Bar. A causa della presenza di sottotipi, questo è necessario.

In Haskell non ci sono sottotipi. L'equivalente di Option in Haskell, chiamato Maybe, ha questa definizione:

data Maybe a = Nothing | Just a 

il tipo di variabile a può essere solo un tipo, quindi non maggiori informazioni su che è necessario.

6

Come accennato, Haskell non ha sottotipi. Tuttavia, se stai guardando le classi di caratteri, potrebbe non essere chiaro come funzioni senza sottotitoli.

I tipiecipali specificano i predicati sui tipi, non sui tipi stessi. Pertanto, quando una classe di genere ha una superclasse (ad es. Eq a => Ord a), ciò non significa che le istanze sono sottotipi, poiché solo i predicati vengono ereditati, non i tipi stessi.

Inoltre, co-, contro- e inversione significano cose diverse in diversi campi della matematica (vedere Wikipedia). Per esempio i termini covariante e controverso sono usati nei funtori (che a loro volta sono usati in Haskell), ma i termini significano qualcosa di completamente diverso. Il termine invariante può essere usato in molti posti.

Problemi correlati