8. Das Typsystem von PVS Zur Erinnerung: das Typsystem in PVS umfaßt - vordefinierte Typen: bool, int usw. - Deklaration von Typnamen für - neue uninterpretierte Typen - interpretierte Typen als Synonyme für Typen oder Typausdrücke - Typausdrücke: - Funktionstypen - Tupel (kartesische Produkte) - Abstrakte Datentypen - Untertypen: für ein Prädikat p: [T -> bool] - subt: TYPE = { x:T | p(x) } - (p) Maschinelles Beweisen mit PVS 8–1 Typen in PVS: Ergänzungen (1) Typ-Deklarationen - von Nichtleeren Typen: Deklaration mit TYPE+ oder NONEMPTY TYPE; zum Nachweis der Nichtleerheit kann ein Element mit CONTAINING angegeben werden: nonzero int: NONEMPTY TYPE = {i: int | i /= 0 } CONTAINING 1 - von uninterpretierten Untertypen: s : TYPE FROM t Aufzählungstypen der Form enum: TYPE = {e 1, ..., e n} Die Namen e i müssen paarweise verschieden sein. wirklich eine spezielle Form einer DATATYPE Spezifikation ; entsprechende Deklarationen und Axiome werden generiert Maschinelles Beweisen mit PVS 8–2 Typen in PVS: Ergänzungen (2) Record-Typen als weitere Typausdrücke: [# a1 : t1, . . . an : tn #] Die ti sind Typ-Ausdrücke, die ai die Bezeichner der Record-Felder. Beispiel: pair: TYPE = [# li, re: nat #] Elemente von Record-Typen werden bezeichnet durch Ausdrücke der Form: (# a1 := e1,..., an := en #) Die Reihenfolge der Record-Elemente (Felder) muß nicht eingehalten werden; durch die Feldnamen bleiben Record-Ausdrücke eindeutig. Die Feldnamen werden zur Selektion von Record-Elementen verwendet mit spezieller Syntax: p: pair = (# li:=5, re:=3 #) p’li ; 5 Maschinelles Beweisen mit PVS 8–3 Typen in PVS: Ergänzungen (3) Typen können von Werten abhängen, d.h. parametrisiert sein. Beispiele aus dem prelude: m: VAR nat upto(m): NONEMPTY TYPE = {n: nat | n <= m} CONTAINING m below(m): TYPE = {n: nat | n < m} auch mit mehreren Parametern: i,j: VAR int subrange(i, j): TYPE = {k: int | i <= k AND k <= j} Ein subrange-Typ kann offensichtlich auch leer sein. Maschinelles Beweisen mit PVS 8–4 Typen in PVS: Abhängige Typen Ein Typ ist ein abhängiger Typ (engl. dependent types), wenn eine Komponente vom Wert einer vorherigen Komponente abhängt. Beispiel: datum: TYPE = [# jj: jahr, mm: monat, tt: {t: posnat | t <= tage(mm,jj) } #] Der Typ der Tag-Komponente tt des Datums hängt von den Werten für das Jahr und den Monat ab, hier ausgedrückt durch eine (geeignet definierte) Funktion tage. Maschinelles Beweisen mit PVS 8–5 Abhängige Typen (2) Beispiel aus dem prelude: Typ der endlichen Folgen (engl. finite sequences): finite sequence: TYPE = [# length: nat, seq: [below[length] -> T] #] Operationen mit endlichen Folgen: z.B. Verkettung o(fs1, fs2): finseq = LET l1 = fs1‘length, lsum = l1 + fs2‘length IN (# length := lsum, seq := (LAMBDA (n:below[lsum]): IF n < l1 THEN fs1‘seq(n) ELSE fs2‘seq(n-l1) ENDIF) #); Maschinelles Beweisen mit PVS 8–6 Abhängige Typen (3) Abhängige Typen zur Verschärfung bzw. genaueren Spezifikation von Definitions- und Wertebereich von Funktionen: ; Vermeidung von Partialität von Funktionen nth(l:list[T], n: below(length(l))): RECURSIVE T = IF n=0 THEN car(l) ELSE nth(cdr(l), n-1) ENDIF MEASURE length(l) Typüberprüfung stellt sicher, daß nicht versucht wird, auf nicht-existierende Listenelemente zuzugreifen. ; Einschränkung des Definitionsbereichs der Funktion nth Maschinelles Beweisen mit PVS 8–7 Abhängige Typen (4) mod: THEORY i,k: VAR int j: VAR nonzero_int mod(i,j): { k | abs(k) < abs(j)} = ... • Wertebereich ist eingeschränkt in dem Sinn, dass der Rumpf der Funktionsdefinition einen Wert bestimmen muß, der dem angegebenen Typ angehört. • Bei Aufruf des Funktion mod wird dann garantiert, daß der Funktionswert angegebene Eigenschaft hat. • Typinformation für mod bzw. einen Aufruf mod(i,j) kann dem Beweiser übermittelt werden mit dem Kommando TYPEPRED. Maschinelles Beweisen mit PVS 8–8 Abhängige Typen (5) Prädikative Untertypen und abhängige Typen erlauben in gewissem Sinn die Spezifikation von Vor- und Nachbedingungen von Funktionen: P (x , y) => Q(f (x , y), x , y) Ohne abhängige Typen könnten P bzw. Q nur viel einfachere Typinformation enthalten (mehrstellige Prädikate ??) Maschinelles Beweisen mit PVS 8–9 Abhängige Typen (6) Beispiel: Realisierung der abstrakten Struktur stack durch Arrays und Größenindex i,k: VAR int ... istack: TYPE = [# size: nat, elems: [{n:nat | n < size} -> T]#] ne istack: TYPE = {s1: istack | s1’size > 0 } Operationen push und pop, Konstante empty für leeren Stack? Maschinelles Beweisen mit PVS 8 – 10 Abhängige Typen (6a) Beispiel: Realisierung der abstrakten Struktur stack durch Arrays und Größenindex istack: TYPE = [# size: nat, elems: [{n:nat | n < size} -> T]#] ne istack: TYPE = {s1: istack | s1’size > 0 } push(e:T, s:istack): ne istack = (# size := s’size + 1, elems := (LAMBDA (j: below(s’size+1)): IF j < s’size THEN s’elems(j) ELSE e ENDIF) #) pop(e:T, s:ne istack): istack = (# size := s’size-1, elems := (LAMBDA (j: below(s’size-1)): s’elems(j) #) empty: istack = (# size := 0, elems := (LAMBDA (j: nat | FALSE): 0) #) Maschinelles Beweisen mit PVS 8 – 11 Typen in PVS: Judgements Judgements dienen dazu, Typinformation, insbesondere diejenige, die mit prädikativen Untertypen verbunden ist (semantische Typinformation) in einer Form zur Verfügung zu stellen, die der Typechecker ausnutzen kann (“Hilfestellung” für den Typechecker). ; Anzahl zu generierenden TCCs kann (i.a.) reduziert werden Judgements sind formalisierte Typ-Aussagen - führen in der Regel zu TCCs, die nachgewiesen werden müssen Formen von Judgements • Constant Judgements: HAS TYPE • Suntype Judgements: SUBTYPE OF Maschinelles Beweisen mit PVS 8 – 12 Judgements – Beispiele (1) mod: THEORY i,k: VAR int m: VAR posnat n: VAR nat j: VAR nonzero_int mod(i,j): { k | abs(k) < abs(j)} = i - j+floor(i,j) mod_below: JUDGEMENT mod(i,m) HAS TYPE below(m) ... END mod Maschinelles Beweisen mit PVS 8 – 13 Judgements – Beispiele (2) i, j, k: VAR nat n: VAR posnat upfrom_nat_is_nat: JUDGEMENT upfrom(i) SUBTYPE_OF nat upfrom_posnat_is_posnat: JUDGEMENT upfrom(n) SUBTYPE_OF posnat above_nat_is_posnat: JUDGEMENT above(i) SUBTYPE_OF posnat subrange_nat_is_nat: JUDGEMENT subrange(i,j) SUBTYPE_OF nat subrange_posnat_is_posnat: JUDGEMENT subrange(n,j) SUBTYPE_OF posnat Maschinelles Beweisen mit PVS 8 – 14 Judgements – Beispiele (3) injective?(f): bool = (FORALL x1, x2: (f(x1) = f(x2) => (x1 = x2))) surjective?(f): bool = (FORALL y: (EXISTS x: f(x) = y)) bijective?(f): bool = injective?(f) & surjective?(f) bij_is_inj: JUDGEMENT (bijective?) SUBTYPE_OF (injective?) bij_is_surj: JUDGEMENT (bijective?) SUBTYPE_OF (surjective?) bij is inj: JUDGEMENT (bijective?) SUBTYPE OF (injective?) Maschinelles Beweisen mit PVS 8 – 15 Judgements – Beispiele (4) orders [T: TYPE]: THEORY BEGIN x, y: VAR T <=, < : VAR pred[[T, T]] p: VAR pred[T] preorder?(<=): bool = reflexive?(<=) & transitive?(<=) preorder_is_reflexive: JUDGEMENT (preorder?) SUBTYPE_OF (reflexive?[T]) preorder_is_transitive: JUDGEMENT (preorder?) SUBTYPE_OF (transitive?[T]) equiv_is_preorder: JUDGEMENT (equivalence?[T]) SUBTYPE_OF (preorder?) partial_order?(<=): bool = preorder?(<=) & antisymmetric?(<=) dichotomous?(<=): bool = (FORALL x, y: (x <= y OR y <= x)) total_order?(<=): bool = partial_order?(<=) & dichotomous?(<=) total_is_po: Maschinelles Beweisen mit PVS JUDGEMENT (total_order?) SUBTYPE_OF (partial_order?) 8 – 16 Parametrisierte Theorien Parametrisierung möglich mit - Typen - Konstanten (einschließlich Funktionskonstanten) Theorie-Parameter ergeben zum Teil denselben Effekt wie polymorphe Typen z.B. list[T] “polymorpher Typ” der Listen über einem beliebigen Elementtyp T Streng genommen gibt es in PVS keine Typ-Variablen, d.h. in dem Sinn wie es Variable für Grundobjekte, Funktionen, Prädikate usw. gibt Keine Quantifizierung über Typen (das ist aber in komplexeren Typentheorien möglich – z.B. Project Typelab der Abteilung) Maschinelles Beweisen mit PVS 8 – 17