Vorlesung: Praxis der Funktionalen Programmierung


Das Typsystem von Haskell

Vorwort. Es ist eine Praxis- und keine Theorie-Vorlesung, deswegen kann ich hier weder exakt noch vollständig sein. Ich beschreibe lediglich die Wirkung des in Haskell angewandten Systems. Die Grundlagen lernt man bei Prof. Gerber (Funktionale Programmierung I), Prof. Herre (Lambda-Kalkül), beides im nächsten Semester im Angebot.

Ideal: jeder Ausdruck hat genau einen Typ, und der ist vor Programmstart bekannt

Was ist überhaupt der Zweck eines Typsystems für eine Sprache? Sehen wir von Dokumentationszwecken ab, und betrachten nur den Ausführungsaspekt.

Die Typprüfung geht der Programmausführung voraus und garantiert im Idealfall die Termination und Korrektheit des Programms. Das ist natürlich wegen Turing-Vollständigkeit nicht erreichbar. Was wir schaffen, ist aber das Verhindern von Laufzeitfehlern. Was ist das in Haskell? Alle Funktionen sind über Pattern matching definiert, und ein Laufzeitfehler ist ein Funktionsaufruf, dessen Argumente auf kein Pattern der definierenden Klauseln passen.

Beispiel: "True && 100" paßt nicht, weil "(&&)" beiderseits True oder False erwartet. Wir würden das daran erkennen, daß "(&&) :: Bool -> Bool -> Bool", aber "100 :: Integer", und das nicht zusammenpaßt.

Ein Typ ist eine Menge von Konstruktoren (mit Argumenttypen und Stelligkeiten), also eine Sorte einer mehrsortigen Algebra (siehe Dr. Hartwig: Algebraische Grundlagen der Informatik).

Die Sprache Haskell ist so entworfen, daß jeder Ausdruck höchstens einen Typ besitzt. (Die typisierbaren Ausdrücke heißen korrekt). Es gibt einen Algorithmus, nach dem der Compiler/Interpreter entscheidet, ob ein korrekter Ausdruck vorliegt, und dann dessen Typ berechnet. Erst danach vergleicht der Compiler den berechneten Typ mit dem, den der Programmierer an den Ausdruck (die Funktionsdefinition) geschrieben hat.

Grenzen des Typsystems

Nicht alles, was eigentlich funktionieren müßte, bekommt nach diesem System tatsächlich einen Typ. Beispielsweise geht so etwas nicht:
let f p = if p then length else (+1)
in  f True [1,2,3] + f False 4
Die Funktion f müßte zwei verschiedene Typen bekommen, je nach dem Wert ihres ersten Argumentes. Wir sehen zwar, daß in diesem Fall alles gutgeht, aber der Compiler kann das in seinem System nicht verifizieren. Wir können ihn verstehen: im Beispiel stehen True und False explizit da, aber in Wirklichkeit können dort komplizierte Ausdrücke stehen, von denen der Compiler natürlich nicht entscheiden kann, welchen Wert sie ergeben. Damit läßt sich auch Typkorrektheit solcher Konstrukte nicht mehr entscheiden. Deswegen verbietet man das von vorherein.

Es gibt jedoch eine Haskell-ähnliche Sprache Cayenne, in der man das obige Programm (so ähnlich) hinschreiben darf. Das Cayenne-Typsystem ist nicht entscheidbar, aber das ist eine Design-Entscheidung, die man in Kauf nimmt.


best viewed with any browser


http://www.informatik.uni-leipzig.de/~joe/ mailto:joe@informatik.uni-leipzig.de