• Keine Ergebnisse gefunden

Lehrstuhl für Programmierparadigmen

N/A
N/A
Protected

Academic year: 2022

Aktie "Lehrstuhl für Programmierparadigmen"

Copied!
6
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Lehrstuhl für Programmierparadigmen

Sebastian Ullrich Max Wagner

sebastian.ullrich@kit.edu maximilian.wagner@kit.edu

Semantik von Programmiersprachen – SS 2019

http://pp.ipd.kit.edu/lehre/SS2019/semantik

Lösungen zu Blatt 8: Typsicherheit Besprechung: 17.06.2019

1. Welche der folgenden Aussagen sind richtig, welche falsch? (H) (a) [x7→int, y7→bool]`(x + 3 <= 17) || (not y):bool

(b) Im Kontext[x7→bool]ist true == x ist ein typkorrekter Ausdruck.

(c) EJ0 * (x - y)K[x7→5, y7→tt] = 0

(d) Jeder Ausdruckehat in jedem KontextΓ höchstens einen Typτ. (e) Der Typ eines Wertesv ließe sich auch so definieren:

type(v) =τ gdw. Γ`v:τ (f) Es gibt keinen KontextΓ mit

Γ`{ var x = x; z := x }; { var y = x; if (y) then z := 5 else skip }X

(g) WennΓ`cXundhc, σi →1hc0, σ0i mitσ0 : Γ undΓ`c0X, dann auchσ : Γ.

(h) WennΓ`cXundσ : Γ, dann gibt esc0 undσ0 mit hc, σi →1 hc0, σ0i.

Lösung:

(1a) Das hängt vom Syntaxbaum des Ausdrucks ab. Durch die geänderte Grammatik gibt es zwei mögliche Syntaxbäume:

((x + 3) <= 17) || (not y) und (x + (3 <= 17)) || (not y)

Im linken Fall gilt die Aussage, obwohl für+und||keine Typregeln definiert wurden – diese sind nur syntaktischer Zucker und damit automatisch abgedeckt. Ohne syntaktischen Zucker schreibt sich dieser Ausdruck wie folgt:

not ((not ((x - (0 - 3)) <= 17)) && (not (not y)))

Der Ableitungsbaum im Typsystem müsste für diesen Ausdruck aufgestellt werden.

Im rechten Fall gilt die Typaussage nicht, weil int + bool nicht typisierbar ist.

(1b) Falsch.true == x ist zwar ein Ausdruck, aber nicht typkorrekt. e1 == e2 ist syntaktischer Zucker für(e1 <= e2) && (e2 <= e1). Nach den Typregeln für<= müssen e1 unde2 den Typint besitzen.

Wollte man Gleichheit auch für boolesche Ausdrücke, gibt es zwei Möglichkeiten:

i. Explizite Produktion für==in Exp. Dann bräuchte man dafür auch eine eigene Typregel Γ`e1 :τ Γ`e2

Γ`e1 == e2:bool

und entsprechend auch eigene Semantikregeln, Beweisfälle etc.

(2)

ii. Man führt zwei Ersetzungsmöglichkeiten füre1 == e2 ein:

(e1 <= e2) && (e2 <= e1) und (e1 && e2) || ((not e1) && (not e2)) Dann ist es aber unmöglich, mit ==einen eindeutigen Syntaxbaum zu beschreiben. Erst ein Typcheck könnte „unsinnige“ Syntaxbäume eliminieren.

(1c) Falsch. WegenEJx - yK[x7→5, y7→tt] =⊥giltEJ0 * (x - y)K[x7→5, y7→tt] =⊥.

0 ist für* (wiefalse für &&)nicht mehr ein absorbierendes Element.

(1d) Richtig. Formal: WennΓ`e:τ und Γ`e:τ0, dannτ =τ0.

Beweis. Normal bräuchte man Regel-Induktion über Γ ` e : τ (τ0 beliebig). Für unser einfaches Typsystem reicht aber Fallunterscheidung:

• Fälle TNum,TMinus,TTimes:

Zu zeigen: Wenn Γ`e:τ0 (wobeie=n,e=e1 - e2 odere=e1 * e2), dann int=τ0. Beweis durch Regelinversion.

• Fälle TTrue,TLeq,TAnd,TNot: Analog mit bool.

• Fall TVar: Zu zeigen: WennΓ`x:τ0 und Γ(x) =τ, dann τ =τ0. Beweis: Durch Regelinversion gilt Γ(x) =τ0.

Typsysteme, die jeder syntaktischen Einheit höchstens einen Typ zuweisen, heißen mono- morph.

(1e) Falsch. Wie in (1d) gezeigt, ist der Typ eines Ausdrucks zwar eindeutig, aber hier wird wieder Syntax mit abstrakten Werten vermischt. v ist aus Z+B, kein Ausdruck. Richtig wäre z.B. type(v) =τ gdw.Γ` V−1JvK:τ.

(1f) Richtig. Aus den Typregeln ergeben sich folgende widersprüchliche Bedingungen:

• Im vorderen Block muss die lokale Variable x wegen der Initialisierung den gleichen Typ wie die globale Variablex haben. Wegenz := xmussz den gleichen Typ haben wie die lokale Varialbe x. Insgesamt: Γ(z) = Γ(x)

• Da die lokale Variable y des zweiten Blocks als Bedingung auftaucht, muss sie den Typ bool haben. Wegen der Initialisierung mit der globalen Variablex gilt also:Γ(x) =bool.

• Wegen z := 5muss geltenΓ(z) =int.

(1g) Falsch. Dies ist die Umkehrung zur Erhaltung der Zustandskonformanz (Lem. 77). Gegen- beispiel:

Sei Γ = [x7→int]. Dann gilt Γ ` x := 0 X, hx := 0, [x7→tt]i →1 hskip, [x7→0]i mit [x7→0] : Γund Γ`skipX, aber nicht [x7→tt] : Γ.

(1h) Falsch. Dies ist nurfast das Fortschrittslemma 76. Für den Fall c=skipgilt es nicht.

2. Ausgaben (H)

Erweitern Sie die SpracheWhileT um Ausgaben:

(a) Ergänzen Sie die Syntax um eine neue Anweisungprint e für Ausgaben.

(b) Passen Sie die Typ-Regeln an. Sowohl Zahlen als auch Wahrheitswerte sind als Ausgabe erlaubt.

(c) Ändern Sie die Big-Step-Semantik, sodass die neue Auswertungsrelation hc, σi ⇓o σ0 die Anweisung c im Anfangszustand σ zum Endzustand σ0 auswertet, wobei die Liste der Ausgabeno entsteht.

(d) Passen Sie auch die Small-Step-Semantik an Ausgaben an. Unterscheidet sie sich in der Ausdrucksmächtigkeit von der Big-Step-Semantik?

(e) Ist die erweiterte Sprache typsicher? Begründen Sie!

Lösung:

(2a) Man braucht nur die Anweisungssyntax zu erweitern:

(3)

Com c ::= skip |x := e|c1; c2 |if (e) then c1 else c2 |while (e) do c| { var x = e; c } |print e

(2b) Neue Typregel:

TPrint: Γ`e:τ Γ`print eX (2c) Man muss jede Regel anpassen – auch erst einmal fürWhileT:

SkipOBS:hskip, σi ⇓[] σ AssOBS: EJeKσ =v hx := e, σi ⇓[] σ[x7→v]

SeqOBS: hc1, σi ⇓o1 σ0 c2, σ0

o2 σ00 hc1; c2, σi ⇓o1++o2 σ00

IfTTOBS: EJeKσ=tt hc1, σi ⇓oσ0 hif (e) then c1 else c2, σi ⇓oσ0

IfFFOBS: EJeKσ=ff hc2, σi ⇓oσ0 hif (e) then c1 else c2, σi ⇓oσ0

WhileFFOBS: EJeKσ =ff

hwhile (e) do c, σi ⇓[] σ

WhileTTOBS: EJeKσ=tt hc, σi ⇓o1 σ0

while (e) do c, σ0

o2 σ00 hwhile (e) do c, σi ⇓o1++o2 σ00

BlockOBS: EJeKσ=v hc, σ[x7→v]i ⇓o σ0 h{ var x = e; c }, σi ⇓oσ0[x7→σ(x)]

Die neue Regel für print e:

PrintOBS: EJeKσ =v hprint e, σi ⇓[v]σ

(2d) Auch die Small-Step-Relationhc, σi→ hco 0, σ0i muss komplett angepasst werden. Über dem Pfeil steht jetzt die Ausgabe des aktuellen Schritts (als maximal einelementige Liste).

AssOSS: EJeKσ=v

hx := e, σi→ hskip, σ[x[] 7→v]i

PrintOSS: EJeKσ =v

hprint e, σi→ hskip, σi[v]

Seq1OSS: hc1, σi→ hco 01, σ0i

hc1; c2, σi→ hco 01; c2, σ0i IfTT

O

SS: EJeKσ=tt

hif (e) then c1 else c2, σi→ hc[] 1, σi

Seq2OSS:hskip; c, σi→ hc, σi[] IfFFOSS: EJeKσ=ff

hif (e) then c1 else c2, σi→ hc[] 2, σi

WhileOSS:hwhile (e) do c, σi→ h[] if (e) then c; while (e) do c else skip, σi

Block1OSS: EJeKσ =v hc, σ[x7→v]i→ hco 0, σ0i h{ var x = e; c }, σi→ h{ varo x = V−1q

σ0(x)y

; c0 }, σ0[x7→σ(x)]i

(4)

Block2OSS: EJeKσ 6=⊥

h{ var x = e; skip }, σi→ h[] skip, σi

Jetzt muss man auch die Semantik durch Ableitungsfolgen anders definieren. Eine endliche Ableitungsfolgehc0, σ0i→ hco0 1, σ1i→o1 . . .o→ hcn−1 n, σnifassen wir nun mithc, σi→o hc0, σ0i zusammen, wobei o =o0++o1++. . . on−1. Entsprechend verkürzen wir eine unendliche Ableitungsfolge hc0, σ0i→ hco0 1, σ1i→o1 . . . auf hc0, σ0i→o , wobeio=o0++o1++. . ..

Big- und Small-Step-Semantik sind jetzt nicht mehr gleich ausdrucksstark: Die Ausgaben nichtterminierender Programme sind in der Small-Step-Semantik ausdrückbar; in der Big- Step-Semantik gibt es nur Nichtableitbarkeit, aber keine Unterscheidung der generierten Ausgaben.

(2e) Ja, die neue Sprache ist typsicher. Der Typsicherheitsbeweis mit Fortschrittslemma, Erhaltung der Zustandskonformanz und Subject Reduction lässt sich leicht um die neuen Fälle für print eergänzen. Die zusätzlichen Ausgaben in allen Regeln werden von Typsystem und Konformanz ignoriert und führen auch keine neuen Bedingungen in den Small-Step-Regeln durch die Hintertür ein.

3. Typsicherheit mit der Big-Step-Semantik (Ü)

Typsicherheit lässt sich auch für eine Big-Step-Semantik zeigen, in dieser Aufgabe für WhileT: (a) Ändern Sie die Auswertungsrelation so, dass eine Anweisung mit einem Zustand statt zu

einem Endzustand auch zu einem speziellen Fehlerwert Errauswerten kann. Fügen Sie nun für jede Regel, die einen Typcheck (implizit) durchführt, eine neue Regel für den Fehlerfall hinzu. Vergessen Sie auch nicht Propagationsregeln für den TypfehlerErr.

(b) Zeigen Sie, dass typkorrekte Programme von konformanten Zuständen aus nie Typfehler erzeugen: WennΓ`cX,σ: Γ undhc, σi ⇓σ¯0, dann σ¯06=Errundσ¯0 : Γ.

(c) Vergleichen Sie diesen Ansatz, Typsicherheit einer Sprache zu zeigen, mit dem Small-Step- Ansatz aus der Vorlesung.

Lösung:

(3a) Unterscheidung in korrekte Auswertungσ und TypfehlerErr:

h·, ·i ⇓ · ⊆Com×Σ×(Σ +{Err})

Normale Regeln der Big-Step-Semantik mit der Variablenkonventionσ¯∈(Σ +{Err}):

SkipTBS:hskip, σi ⇓σ AssTBS: EJeKσ =v

hx := e, σi ⇓(σ[x7→v])

SeqTBS: hc1, σi ⇓σ0 c2, σ0

⇓σ¯00 hc1; c2, σi ⇓σ¯00

IfTTTBS: EJeKσ =tt hc1, σi ⇓σ¯0 hif (e) then c1 else c2, σi ⇓σ¯0

IfFFTBS: EJeKσ =ff hc2, σi ⇓σ¯0 hif (e) then c1 else c2, σi ⇓σ¯0

WhileFFTBS: EJeKσ =ff hwhile (e) do c, σi ⇓σ

(5)

WhileTTTBS: EJeKσ=tt hc, σi ⇓σ0

while (e) do c, σ0

⇓σ¯00 hwhile (e) do c, σi ⇓σ¯00

BlockTBS: EJeKσ =v hc, σ[x7→v]i ⇓σ0 h{ var x = e; c }, σi ⇓(σ0[x7→σ(x)])

Anmerkung zu den Änderungen: Ergebnisse müssen immer die Formσ oderErr haben.

Wenn das Resultat einer Regel weiterverarbeitet werden soll (in weiteren Prämissen wie SeqTBS undWhileTTTBS oder durch Änderung des Zustands wie inBlockTBS), dann darf dies nur bei normaler Auswertungσ möglich sein.

Und jetzt noch die ganzen Regeln für Typfehler (keine vergessen!):

AssErrBS : EJeKσ=⊥

hx := e, σi ⇓Err Seq

Err

BS : hc1, σi ⇓Err hc1; c2, σi ⇓Err

IfErrBS : EJeKσ /∈B

hif (e) then c1 else c2, σi ⇓Err

WhileErrBS 1: EJeKσ /∈B

hwhile (e) do c, σi ⇓Err While

Err2

BS : EJeKσ =tt hc, σi ⇓Err hwhile (e) do c, σi ⇓Err

BlockErrBS 1: EJeKσ=⊥

h{ var x = e; c }, σi ⇓Err Block

Err2

BS : EJeKσ =v hc, σ[x7→v]i ⇓Err h{ var x = e; c }, σi ⇓Err (3b) Diese Aussage beinhaltet im Wesentlichen den Beweis zur Zustandskonformanzerhaltung bei

Small-Step (Lem. 77).

Zu zeigen: Wennhc, σi ⇓σ¯0 mit Γ`cXund σ: Γ, dann ist σ0 von der Form σ00 mitσ00: Γ.

Beweis. Regel-Induktion überhc, σi ⇓σ¯0 (Γbeliebig). Wegen der nichtterminierenden Regel WhileTTTBS ist dies die einzige Beweismöglichkeit.

• Fälle SkipTBS,WhileFFTBS: Trivial.

• Fall AssTBS: Beweis analog zur Zustandskonformanzerhaltung bei Small-Step (Lem. 77).

• Fall AssErr

BS : Aus Γ ` x := e X erhält man durch Regelinversion (TAss) ein τ mit Γ(x) =τ undΓ`e:τ. Zusammen mitσ: Γgilt nach Lem. 75:EJeKσ6=⊥. Widerspruch zur FallannahmeEJeKσ =⊥.

• Fall SeqT

BS: Induktionsannahmen:

(i) WennΓ`c1 Xundσ : Γ, dann istσ0 von der Form. . . naja, ist ja schon von der Form.

Wir erhalten allerdings noch σ0: Γ.

(ii) WennΓ`c2Xund σ0 : Γ, dann istσ¯00 von der Form σ000 mit σ000 : Γ.

Zu zeigen: Wenn Γ`c1; c2 Xund σ: Γ, dann ist σ¯00 von der Formσ000 mitσ000 : Γ.

Aus Γ`c1; c2 Xerhält manΓ`c1 Xund Γ`c2 Xdurch Regelinversion (TSeq).

Mitσ: Γfolgt nach Induktionsannahme (i), dassσ0: Γ(hier benötigt man den Erhalt der Zustandskonformanz). Aus Induktionsannahme (ii) folgt dann direkt die Behauptung.

• Fall SeqErrBS : Induktionsannahme: WennΓ`c1 Xund σ: Γ, dann istErrvon der Form σ0 mitσ0 : Γ.

Zu zeigen: Wenn Γ`c1; c2 Xund σ: Γ, dann ist Errvon der Form σ0 mit σ0 : Γ.

Regelinversion auf Γ`c1; c2 XliefertΓ`c1X. Damit kann man die die Induktionsan- nahme anwenden, die eine absurde Aussage liefert, und eine absurde Aussage ist so gut wie jede andere.

• Fall WhileTTTBS: Induktionsannahmen:

(i) Wenn Γ`cXundσ : Γ, dann ist σ0 von eben der Form und σ0 : Γ.

(ii) Wenn Γ`while (e) do cXundσ0 : Γ, ist σ¯00 von der Form σ000 mit σ000: Γ.

Zu zeigen: Wenn Γ`while (e) do cXund σ: Γ, ist σ¯00 von der Formσ000 mit σ000: Γ.

(6)

Aus Γ`while (e) do cXfolgt Γ`cX. Mit Induktionsannahme (i) erhält man wieder σ0 : Γ. Induktionsannahme (ii) liefert die Behauptung.

Dieser Fall ist ähnlich zu SeqTBS, braucht aber die Induktion über hc, σi ⇓ σ¯0 für die Induktionsannahme (ii), deren Anweisung nicht kleiner ist als die Konklusion.

• Fall WhileErrBS 1: Aus Lem. 75 folgt mit Γ ` e :B (RegelinversionTWhile) und σ : Γ, dassEJeKσ=v mitv∈B. Widerspruch zur Fallannahme EJeKσ /∈B.

• Fälle WhileErr2

BS ,BlockErr2

BS : Analog zuSeqErr

BS .

• Fälle IfTTTBS,IfFFTBS,IfErrBS : Analog zu while.

• Fall BlockTBS: Analog zur Erhaltung der Zustandskonformanz in Lem. 77. Induktionsan- nahme brauchtΓ beliebig.

• Fall BlockErrBS 1: Analog zu AssErrBS .

(3c) Typfehler werden in der Small-Step-Semantik durch Blockieren modelliert. Bei Big-Step ist dies nicht möglich, da Nichtableitbarkeit auch durch Nichttermination entstehen kann.

Vorteile Big-Step:

• Intuitiverer Ansatz, da Typfehler explizit modelliert werden.

• Beweis insgesamt einfacher, da kein Fortschritts- oder Subject-Reduction-Lemma gezeigt werden muss.

Nachteile Big-Step:

• Massive Veränderung an der Semantik nötig, i.d.R. doppelt so viele Regeln (und damit auch Beweis-Fälle in jedem Beweis über die Big-Step-Semantik.

• Typfehlerregeln sind semantisch irrelevant, weil für typkorrekte Programme nie anwend- bar. Deswegen gehören sie auch nicht in die Semantik.

• Keine Kontrolle, ob wirklich alle Typfehlerregeln eingefügt wurden.

Referenzen

ÄHNLICHE DOKUMENTE

Beachten Sie, dass sich diese Implementierung nicht direkt mit der Implementierung von for mittels while kombinieren lässt, da auch bei continue die Zählvariable erhöht werden

Typsicherheit lässt sich auch für eine Big-Step-Semantik zeigen, in dieser Aufgabe für While T : (a) Ändern Sie die Auswertungsrelation so, dass eine Anweisung mit einem Zustand

Dementsprechend kann die Semantik des rekursiven Falls (und alle Approximationen daran) nur ⊥ sein, denn eine solche Schleife

R ist total geordnet, damit auch das Intervall, somit ist jede Teilmenge eine Kette.. Sei also M ⊆

Damit kann man dann auch die denotationale Semantik eines Programms c zu einer Funktion Σ → (P(Σ) × B ) erweitern, wobei das boolesche Flag angibt, ob c für den

In dieser Aufgabe sollen Sie nun eine denotationale Fortsetzungssemantik für

In einer früheren Aufgabe haben wir schon die operationale Semantik einer repeat-Schleife

In dieser Aufgabe sollen Sie nun eine denotationale Fortsetzungssemantik für