Erstklassige Typen ermöglichen eine sogenannte abhängige Typisierung . Diese ermöglichen es dem Programmierer, Werte von Typen auf Textebene zu verwenden. Beispielsweise ist der Typ aller Ganzzahlpaare ein regulärer Typ, während das Paar aller Ganzzahlen mit der linken Zahl, die kleiner als die rechte Zahl ist, ein abhängiger Typ ist. Das Standard-Einführungsbeispiel hierfür sind längencodierte Listen (normalerweise Vector
in Haskell / Idris genannt). Der folgende Pseudocode ist eine Mischung aus Idris und Haskell.
-- a natural number
data Nat = Zero | Successor Nat
data Vector length typ where
Empty : Vector Zero typ
(::) : typ -> Vector length typ -> Vector (Successor length) typ
Dieser Code sagt uns zwei Dinge:
- Die leere Liste hat die Länge Null.
cons
Wenn Sie ein Element in eine Liste aufnehmen, wird eine Längenliste erstellt n + 1
Das sieht einem anderen Konzept mit 0 sehr ähnlich und n + 1
nicht wahr? Ich werde darauf zurückkommen.
Was gewinnen wir daraus? Wir können jetzt zusätzliche Eigenschaften der von uns verwendeten Funktionen bestimmen. Beispiel: Eine wichtige Eigenschaft von append
ist, dass die Länge der resultierenden Liste die Summe der Längen der beiden Argumentlisten ist:
plus : Nat -> Nat -> Nat
plus Zero n = n
plus (Successor m) n = Successor (plus m n)
append : Vector n a -> Vector m a -> Vector (plus n m) a
append Empty ys = ys
append (x::xs) ys = x :: append xs ys
Alles in allem scheint diese Technik in der täglichen Programmierung nicht allzu nützlich zu sein. Wie hängt das mit Sockets, POST
/ GET
Anfragen usw. zusammen?
Nun, das tut es nicht (zumindest nicht ohne großen Aufwand). Aber es kann uns auf andere Weise helfen:
Abhängige Typen ermöglichen es uns, Invarianten in Code-Regeln so zu formulieren, wie sich eine Funktion verhalten muss. Mit diesen erhalten wir zusätzliche Sicherheit für das Verhalten des Codes, ähnlich wie bei Eiffels Vor- und Nachbedingungen. Dies ist äußerst nützlich für die automatisierte Theoremprüfung, die eine der möglichen Anwendungen für Idris darstellt.
Zurück zum obigen Beispiel: Die Definition von längencodierten Listen ähnelt dem mathematischen Konzept der Induktion . In Idris können Sie das Konzept der Induktion auf einer solchen Liste wie folgt formulieren:
-- If you can supply the following:
list_induction : (Property : Vector len typ -> Type) -> -- a property to show
(Property Empty) -> -- the base case
((w : a) -> (v : Vector n a) ->
Property v -> Property (w :: v)) -> -- the inductive step
(u : Vector m b) -> -- an arbitrary vector
Property u -- the property holds for all vectors
Diese Technik beschränkt sich auf konstruktive Beweise, ist aber dennoch sehr leistungsfähig. Sie können versuchen, append
als Übung induktiv zu schreiben .
Abhängige Typen sind natürlich nur eine Verwendung erstklassiger Typen, aber es ist wohl eine der häufigsten. Weitere Verwendungszwecke sind beispielsweise die Rückgabe eines bestimmten Typs von einer Funktion anhand ihrer Argumente.
type_func : Vector n a -> Type
type_func Empty = Nat
type_func v = Vector (Successor Zero) Nat
f : (v : Vector n a) -> type_func v
f Empty = 0
f vs = length vs :: Empty
Dies ist ein unsinniges Beispiel, aber es zeigt etwas, das Sie ohne erstklassige Typen nicht emulieren können.