L'inferenza di Hindley-Milner potrebbe funzionare per la lingua Go?


22

Ho letto che Hindley-Milner non funziona con i sistemi di tipo che hanno sottoclassi e ci sono anche altre caratteristiche di sistema di tipo che non funzionano bene con esso. Go attualmente ha solo un'inferenza di tipo molto limitata nell'operatore :=. Ma Go non ha sottoclassi in senso tradizionale, solo interfacce che assomigliano molto alle classi di tipo di Haskell che funzionano bene con l'inferenza Hindley-Milner.

Quindi, l'inferenza di Hindley-Milner potrebbe funzionare in linea di principio per Go allo stesso modo di Haskell? O Go ha altre funzionalità che lo rompono? (D'altra parte, Haskell ha anche alcune funzionalità che non funzionano con Hindly-Milner, se usi quelle devi digitare manualmente quelle parti del tuo programma.)

Risposte:


35

L'inferenza di tipo Hindley-Milner viene utilizzata per i sistemi di tipo Hindley-Milner, una limitazione dei sistemi di tipo F-System. La caratteristica interessante dei sistemi di tipo HM è che hanno un polimorfismo parametrico (alias generici). Questa è la caratteristica del sistema di tipo più grande che Golang rifiuta di avere.

Con quella frustrante restrizione, l'inferenza di tipo HM è impossibile. Diamo un'occhiata al codice non tipizzato:

func f(a) {
  return a.method()
}

Di che tipo è f? Si potrebbe notare che adeve avere un metodo, così abbiamo potuto utilizzare un'interfaccia anonimo: func f(a interface { method() ??? }) ???. Tuttavia, non abbiamo idea di quale sia il tipo restituito. Con le variabili di tipo, potremmo dichiarare il tipo come

func f[T](a interface{ method() T }) T

Tuttavia, Go non ha variabili di tipo, quindi non funzionerà. Mentre le interfacce implicite semplificano alcuni aspetti dell'inferenza dei tipi, ora non abbiamo modo di scoprire il tipo restituito di una chiamata di funzione. Il sistema HM richiede che tutte le funzioni siano dichiarate piuttosto che implicite, e ogni nome può avere un solo tipo (mentre i metodi di Go possono avere tipi diversi in interfacce diverse).

Al contrario, Go richiede che le funzioni siano sempre dichiarate completamente, ma consente alle variabili di utilizzare l'inferenza di tipo. Ciò è possibile perché il lato destro di un compito variable := expressionha già un tipo noto in quel punto del programma. Questo tipo di inferenza di tipo è semplice, corretto e lineare.

  • Il tipo di una variabile è immediatamente noto al momento della dichiarazione, mentre l'inferenza HM deve potenzialmente verificare prima di tutto l'intero programma. Ciò ha un impatto notevole anche sulla qualità dei messaggi di errore.
  • L'approccio di inferenza del tipo di Go selezionerà sempre il tipo più specifico per una variabile, a differenza di HM che seleziona il tipo più generale. Funziona in modo pulito con il sottotipo, anche con le interfacce implicite di Go.

24
@bishop È "ragionato" per infinitamente piccoli valori di "ragione".
Hobbs,

18
@bishop Dopo aver svolto il lavoro di compilatore in lingue con generici, posso certamente essere d'accordo: è difficile da implementare senza complicare significativamente l'implementazione. Andrei al punto di sostituire anche "difficile" con "impossibile". Tuttavia, non è questo il punto; il punto è, vale la complicazione in più? E la risposta, a chiunque abbia lavorato con e senza generici, è ovviamente "sì, sicuramente!" Dovrei essere pienamente d'accordo con l'affermazione che rifiutare di attuare i generici perché "oh no, la complessità" è idiota.
Mason Wheeler,

18
Questo è anche il motivo per cui gli sviluppatori Go fanno finta che FP di ogni sorta sia negativo; Go ha funzioni di prima classe con chiusura lessicale, e con questo la capacità di creare funzioni di ordine superiore, ma è impossibile metterle a qualsiasi uso buono, perché la tipologia di tali funzioni di base come map, filtere reducesono tutti indicibile entro Go molto limitata sistema di tipo.
Hobbs,

9
@hobbs And Go potrebbe essere un linguaggio davvero carino se fosse risolto, ma invece le persone devono scrivere librerie di generazione generica come gengenegonerics
cat

14
@cat È un peccato. All'inizio Go sembra un grande linguaggio pieno di grandi idee, ma poi ti rendi conto che non ha ereditarietà e polimorfismo, quindi non puoi fare OOP bene e non ha generici, quindi non puoi fare bene FP e tu sei rimasto a fissare lo schermo senza dire "allora come dovresti usare esattamente questa lingua?!?"
Mason Wheeler,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.