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 a
deve 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 := expression
ha 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.