Typinferenz in Golang / Haskell

9

Ich habe gelesen, dass Go keine echte Typinferenz in dem Sinne hat, wie es funktionale Sprachen wie ML oder Haskell haben, aber ich konnte keinen einfach zu verstehenden Vergleich der beiden Versionen finden. Könnte jemand in grundlegenden Begriffen erklären, wie sich die Typinferenz in Go von der Typinferenz in Haskell unterscheidet und welche Vor- und Nachteile sie haben?

a3onstorm
quelle

Antworten:

13

Siehe diese StackOverflow-Antwort bezüglich der Typinferenz von Go. Ich bin mit Go selbst nicht vertraut, aber basierend auf dieser Antwort scheint es ein einseitiger "Typabzug" zu sein (um etwas C ++ - Teminologie auszuleihen). Es bedeutet, dass wenn Sie haben:

x := y + z

Dann wird der Typ von xabgeleitet, indem der Typ von herausgefunden wird y + z, was für den Compiler relativ trivial ist. Um dies zu tun, werden die Typen yund zmüssen bekannt sein , a priori : dies über Typenannotationen getan werden könnte , oder von den Literalen zugewiesen , um sie zu entnehmen.


Im Gegensatz dazu haben die meisten funktionalen Sprachen eine Typinferenz, die alle möglichen Informationen innerhalb eines Moduls (oder einer Funktion, wenn der Inferenzalgorithmus lokal ist) verwendet, um den Typ der Variablen abzuleiten. Komplizierte Inferenzalgorithmen (wie Hindley-Milner) beinhalten häufig eine Form der Typvereinigung (ein bisschen wie das Lösen von Gleichungen) hinter den Kulissen. Zum Beispiel in Haskell, wenn Sie schreiben:

let x = y + z

dann kann Haskell den Typ nicht nur, xsondern auch yund zeinfach basierend auf der Tatsache ableiten , dass Sie eine Addition an ihnen durchführen. In diesem Fall:

x :: Num a => a
y :: Num a => a
z :: Num a => a

(Der Kleinbuchstabe abezeichnet hier einen polymorphen Typ , der in anderen Sprachen wie C ++ häufig als "Generika" bezeichnet wird. Der Num a =>Teil ist eine Einschränkung , die angibt, dass die aTypunterstützung einen Zusatzbegriff hat.)

Hier ist ein interessanteres Beispiel: Der Festkomma-Kombinator, mit dem jede rekursive Funktion definiert werden kann:

let fix f = f (fix f)

Beachten Sie, dass wir fweder den Typ noch den Typ angegeben haben fix, der Haskell-Compiler jedoch automatisch Folgendes herausfinden kann:

f :: t -> t
fix :: (t -> t) -> t

Dies sagt, dass:

  • Der Parameter fmuss eine Funktion von einem beliebigen Typ tzum selben Typ sein t.
  • fixist eine Funktion, die einen Parameter vom Typ Typ empfängt t -> tund ein Ergebnis vom Typ zurückgibt t.
Rüschenwind
quelle
4
genauer gesagt, kann Haskell , dass sagen x, y, zist der gleiche Numeric Art, aber sie können immer noch seine Integers, Doubles, Ratio Integers ... Haskell ist bereit , eine willkürliche Wahl zwischen numerischen Typen zu machen, aber nicht für anderen typeclasses.
John Dvorak
7

Die Typinferenz in Go ist äußerst begrenzt und äußerst einfach. Es funktioniert nur in einem Sprachkonstrukt (Variablendeklaration) und nimmt einfach den Typ der rechten Seite und verwendet ihn als Typ für die Variable auf der linken Seite.

Die Typinferenz in Haskell kann überall verwendet werden. Sie kann verwendet werden, um die Typen für das gesamte Programm abzuleiten. Es basiert auf der Vereinheitlichung, was bedeutet, dass (konzeptionell) alle Typen "auf einmal" abgeleitet werden und sich gegenseitig beeinflussen können: In Go können Typinformationen nur von der rechten Seite einer Variablendeklaration nach links fließen. Seite, niemals in die andere Richtung und niemals außerhalb einer Variablendeklaration; In Haskell fließen Typinformationen frei in alle Richtungen durch das gesamte Programm.

Das Typensystem von Haskell ist jedoch so leistungsfähig, dass die Typinferenz tatsächlich nicht auf einen Typ schließen kann (oder genauer gesagt: Es müssen Einschränkungen eingeführt werden, damit ein Typ immer abgeleitet werden kann). Das Typensystem von Go ist so einfach (keine Subtypisierung, kein parametrischer Polymorphismus) und seine Folgerung so begrenzt, dass es immer erfolgreich ist.

Jörg W Mittag
quelle
4
"In Haskell fließen Typinformationen frei in alle Richtungen durch das gesamte Programm": Ich finde, dass dies eine sehr gute Intuition ergibt. +1
Giorgio
Die Behauptungen, die diese Antwort im letzten Absatz macht, sind etwas irreführend. Haskell hat keine Untertypisierung. Darüber hinaus verursacht der parametrische Polymorphismus kein Problem für die Vollständigkeit der Typinferenz: Hindley-Milner findet in der polymorphen Lambda-Rechnung immer den allgemeinsten Typ. Haskell kann möglicherweise keine Typen ableiten, dies gilt jedoch für hochentwickelte Typsystemfunktionen wie GADTs, bei denen bei naiver Formulierung kein Haupttyp (dh "beste Wahl") vorhanden ist.
Edward Z. Yang