Nachdem wir bereits Erfahrung mit operationalen Semantiken gemacht haben, können
wir das einfach getypte λ-Kalkül nun gleich anhand seiner operationalen Semantik
erklären. Im Vergleich zum ungetypten λ-Kalkül sind die Terme praktisch
die gleichen geblieben. Es wurde nur ein primitiver Wert unit
ergänzt
und eine Typzuweisung für das Argument in die Funktionsabstraktion aufgenommen
(λx:T.t
). Die Auswertungsfunktion hat sich nicht
geändert.
Es gibt nun eine beliebig große Anzahl von konkreten Typen T
wie zum Beispiel:
|
Betrachten wir nun die Typregeln.
Das Axiom (4) besagt, dass der Wert
unit
in jedem Kontext den Typ Unit hat.
Regel (1) besagt, dass die Variable
x im Kontext Γ den Typ T
hat, wenn es im Kontext Γ eine Variable-Typ
Bindung x:T
gibt. Diese Regel mag zunächst obsolet erscheinen. Sie ist
jedoch notwendig als Brücke zwischen Variablen, deren Typbindungen Elemente des Kontexts sind,
und allgemeinen Termen, deren Typen sich aus dem Kontext berechnen lassen.
Regel (2) beschreibt die Funktionsabstraktion. Innerhalb der Funktion (in der Prämisse) gibt
es die Variable Typ-Bindung x:T
. Ausserhalb der Funktion ist die
Variable x
nicht mehr an den Typ T
gebunden.
Regel (4) beschreibt die Funktionsapplikation. Zu beachten ist die Verwendung der
Metavariablen T1
in der Prämisse.
Wir können nun ganz mechanisch einen Typableitungsbaum für den Term (λx:Unit.x) unit
konstruieren:
Über den Bruchstrichen steht jeweils die Prämisse unter den Bruchstrichen die Folgerung. Neben jedem Bruchstrich steht die Nummer der angewendeten Regel. Die Folgerungen der vorangegangenen Regeln bilden die Prämisse für die nächste Regel. _ |- steht für {} |-. Klammern wurden bei Bedarf ergänzt.
Terme für die ein Typableitungsbaum existiert bezeichnen wir als wohlgetypt.
Vergleichen wir die Eigenschaften des einfach getypten λ-Kalküls mit den Eigenschaften des ungetypten λ-Kalküls
Werte sind in Terme in Normalform:
Gilt aus den gleichen Überlegungen wie im ungetypten Fall.
Jeder Term in Normalform ist ein Wert:
Gilt aus den gleichen Überlegungen wie im ungetypten Fall.
Die Auswertung (→) erfolgt deterministisch:
Gilt aus den gleichen Überlegungen wie im ungetypten Fall.
Jeder wohlgetypte Term hat eine Normalform:
Diese Eigenschaft gilt für dieses Kalkül wieder (ohne Beweis). Natürlich
ist es keine allgemeine Eigenschaft von typisierten Sprachen, dass ihre Programme
immer terminieren. In unserem Fall ist die Terminierung eine Folge
der verringerten Ausdruckskraft im Vergleich zum ungetypten Kalkül.
Zur Veranschaulichung betrachten wir den Term:
|
x
zu bestimmen. Hat x
beispielsweise
den Typ U
muss es nach Regel (3) auch den Typ U→T haben. Das geht aber
nicht. Also hat x
keinen Typ.
Wir wollen nun zwei weitere Eigenschaften betrachten, die zusammengenommen die Typsicherheit ausmachen.
Progress (Fortschritt):
Wohlgetypte Terme sind entweder in Normalform (d.h. sie sind
Werte) oder sie können noch einen Auswertungsschritt durchlaufen
(d.h. es gibt ein t' so dass t→t').
Preservation (Typerhaltung):
Der Typ eines Terms bleibt bei jedem Auswertungsschritt erhalten
(d.h. wenn t im Kontext Γ den Typ T hat und es ein t' mit t→t' gibt,
dann hat t' im Kontext Γ auch den Typ T).
Beide Eigenschaften gelten für unsere Sprache.
Implementierung in Haskell
|
Term
haben wir um den Konstruktur TmUnit
für den
Wert unit
und eine Typangabe im Konstruktor erweitert. Typen werden
durch den Datentyp Type
repräsentiert. Der Kontext Γ wird durch eine
Liste aus Variablen-Name und Typ Tupeln repräsentiert. Die Funktionen eval
und SubstTm
sind bis auf den Fall TmUnit
unverändert zur
Implementation im ungetypen λ-Kalkül.
Neu hinzugekommen ist die Funktion typeof
. Für jeden wohlgetypten Ausdruck liefert sie
den Typ. Enthält ein Ausdruck einen Typfehler entsteht eine Exception. In
der Zeile (TyArrow ttp tte) = typeof ctx t1
wird dem Ergebnis
der Typberechnung das Muster (TyArrow _ _)
aufgedrückt. Passt
das Muster nicht (d.h. ist der rechte Term einer Funktionsanwendung keine
Funktion) generiert die Laufzeitumgebung eine relativ unverständliche
Fehlermeldung. Die Fehlermeldungen sind insgesamt verbesserungsfähig. Von
einem echten Typprüfer würden wir uns mehr Informationen darüber wünschen,
wo genau ein Fehler aufgetreten ist.
Neu hinzugekommen ist die Funktion safeEval
die vor der
Auswertung eines Terms eine Typprüfung erzwingt. Das eigentliche eval
ignoriert Typen.
Übung: Male einen Typableitungsbaum für den Ausdruck
(λx:U
→U.x unit)(λx:U.x)
Für Unit
sollte dabei einheitlich U
geschrieben werden.
[Lösung]