Wie verstehe ich die Hindley-Milner-Regeln?
Hindley-Milner ist ein Satz von Regeln in Form von Folgerechnung (nicht natürliche Deduktion), die zeigt, dass wir den (allgemeinsten) Typ eines Programms aus der Konstruktion des Programms ohne explizite Typendeklarationen ableiten können.
Die Symbole und die Notation
Erläutern wir zunächst die Symbole und den Vorrang der Operatoren
-
ist ein Bezeichner (informell: ein Variablenname).
-
: bedeutet ist ein Typ von (informell: ein Fall von oder "ist-a").
-
(sigma) ist ein Ausdruck, der entweder eine Variable oder eine Funktion ist.
-
also : wird gelesen " ist ein "
-
bedeutet "ist ein Element von".
-
(Gamma) ist eine Umgebung.
-
(das Behauptungszeichen) bedeutet behauptet (oder beweist, aber im Kontext liest sich "behauptet" besser.)
-
: lautet also " behauptet, dass , ist-ein "
-
ist eine tatsächliche Instanz (Element) des Typs .
-
(tau) ist ein Typ: entweder grundlegend, variabel ( ), funktional ' oder Produkt ×' (Produkt wird hier nicht verwendet)
-
' ist ein funktioneller Typ, bei dem et ' sind potenziell verschiedene Typen.
-
. bedeutet (lambda) ist eine anonyme Funktion, die ein Argument annimmt, und gibt einen Ausdruck zurück, .
-
lassen Sie \= in bedeutet im Ausdruck, , Ersatz wo immer erscheint.
-
bedeutet, dass das vorherige Element ein Subtyp (informell - Unterklasse) des letzteren Elements ist.
-
ist eine Typvariable.
-
. ist ein Typ, (für alle) Argumentvariablen, und kehrt zurück ひょうげん
-
free() bedeutet, dass es sich nicht um ein Element der im äußeren Kontext definierten Variablen des freien Typs handelt. (Gebundene Variablen sind substituierbar.)
Alles oberhalb der Linie ist die Prämisse, alles unterhalb ist die Schlussfolgerung ( Per Martin-Löf )
Präzedenzfall, zum Beispiel
Ich habe einige der komplexeren Beispiele aus den Regeln genommen und überflüssige Klammern eingefügt, die den Vorrang anzeigen:
-
: könnte geschrieben werden ( : )
-
: geschrieben werden könnte ( : )
-
lassen Sie \= in : ist gleichbedeutend mit (( lassen Sie ( \= ) in ) : )
-
. : ' gleichbedeutend ist (( . ) : ( ' ))
Die großen Abstände zwischen den Aussagen der Behauptung und den anderen Voraussetzungen weisen auf eine Reihe solcher Voraussetzungen hin, und die horizontale Linie, die die Prämisse von der Schlussfolgerung trennt, bildet schließlich das Ende der Rangfolge.
Die Regeln
Es folgen englische Auslegungen der Regeln, jeweils gefolgt von einer lockeren Umformulierung und einer Erläuterung.
Variabel
Gegeben ist ein Typ von (sigma), ein Element von (Gamma),
schließen behauptet, ist ein .
Anders ausgedrückt, in , wissen wir, dass es vom Typ ist, weil es vom Typ in ist.
Dies ist im Grunde eine Tautologie. Ein Bezeichnername ist eine Variable oder eine Funktion.
Funktion Anwendung
Da asserts ein funktionaler Typ ist und asserts eine
folgert, dass die Anwendung der Funktion to ein Typ ' ist
Um die Regel neu zu formulieren, wissen wir, dass die Funktion application den Typ ' zurückgibt, weil die Funktion den Typ ' hat und ein Argument des Typs erhält.
Das heißt, wenn wir wissen, dass eine Funktion einen Typ zurückgibt, und wir sie auf ein Argument anwenden, wird das Ergebnis eine Instanz des Typs sein, von dem wir wissen, dass er zurückgegeben wird.
Funktion Abstraktion
Gegeben und vom Typ asserts ist ein Typ, '
conclude behauptet, dass eine anonyme Funktion, die einen Ausdruck zurückgibt, vom Typ ' ist.
Wenn wir eine Funktion sehen, die einen Ausdruck annimmt und zurückgibt, wissen wir, dass sie vom Typ ' ist, weil (a ) behauptet, dass sie ein ' ist.
Wenn wir wissen, dass is vom Typ ist und somit ein Ausdruck vom Typ ' ist, dann ist eine Funktion, die den Ausdruck zurückgibt, vom Typ '.
Variable Deklaration zulassen
Gegeben sind Behauptungen , vom Typ , und und , vom Typ , behauptet vom Typ
folgern behauptet let
= in
vom Typ
Locker gesagt, ist in (a ) gebunden, weil is a , und is a behauptet, dass is a .
Das heißt, wenn wir einen Ausdruck haben, der a ist (eine Variable oder eine Funktion), und einen Namen, , auch ein , und einen Ausdruck vom Typ , dann können wir für ersetzen, wo immer er innerhalb von erscheint.
Instanziierung
Bei Asserts vom Typ ' und ' ist ein Subtyp von
conclude asserts ist vom Typ
Ein Ausdruck, ist von übergeordnetem Typ, weil der Ausdruck vom Subtyp ' ist und der übergeordnete Typ von ' ist.
Wenn eine Instanz von einem Typ ist, der ein Subtyp eines anderen Typs ist, dann ist sie auch eine Instanz dieses Supertyps - des allgemeineren Typs.
Verallgemeinerung
Gegeben ist ein Assert und ist kein Element der freien Variablen von ,
conclude asserts , type für alle Argumentausdrücke, die einen Ausdruck zurückgeben
So ist im Allgemeinen für alle Argumentvariablen (), die zurückkehren, typisiert, weil wir wissen, dass ist ein und ist keine freie Variable.
Das bedeutet, dass wir ein Programm so verallgemeinern können, dass es alle Typen für Argumente akzeptiert, die nicht bereits im enthaltenden Bereich gebunden sind (Variablen, die nicht lokal sind). Diese gebundenen Variablen sind ersetzbar.
Alles zusammenfügen
Unter bestimmten Annahmen (z. B. keine freien/undefinierten Variablen, eine bekannte Umgebung, ) kennen wir die Typen von:
- atomare Elemente unserer Programme (Variable),
- Werte, die von Funktionen zurückgegeben werden (Function Application),
- funktionale Konstrukte (Funktionsabstraktion),
- let-Bindungen (Let-Variablen-Deklarationen),
- übergeordnete Typen von Instanzen (Instanziierung), und
- alle Ausdrücke (Generalisierung).
Schlussfolgerung
Die Kombination dieser Regeln ermöglicht es uns, den allgemeinsten Typ eines behaupteten Programms zu beweisen, ohne dass Typ-Annotationen erforderlich sind.