Grundlagen der Programmierung 2 (Kap 6) Operationale Semantik

Werbung
Grundlagen der Programmierung 2
(Kap 6)
Operationale Semantik
Prof. Dr. Manfred Schmidt-Schauß
Künstliche Intelligenz und Softwaretechnologie
23. März 2011
Semantik von Programmiersprachen
Semantik = Bedeutung eines Programms (Programmtextes)
ausgehend vom Syntaxbaum des Programms.
Methoden der Semantik-Definition:
Operationale Semantik
Denotationale Semantik
Transformations-Semantik
axiomatische Semantik
Grundlagen der Programmierung 2
- 2 -
Operationale Semantik
Spezifikation von Wirkung und Ablauf:
Zustand:
Pro Programmkonstrukt:
Haskell:
Python:
Zustand
Übergänge:
Zustand
Übergänge:
=
=
=
=
Speicherbelegung als Datenstruktur oder . . .
Angabe des Zustandsübergangs
Ausdruck
Reduktionen, d.h. Änderungen der Ausdrücke.
Umgebung
Veränderungen des Speicherinhalts.
operationale Semantik = Spezifikation eines Interpreters
Vorteil: Prinzipiell immer durchführbar
Grundlagen der Programmierung 2
- 3 -
Denotationale Semantik
Zuordnung:
Programm 7→ Funktion
Domain D:
Menge der möglichen Funktionen
und Objekte
Pro Programmkonstrukt:
rekursive Angabe der Konstruktion einer
Funktion in D.
Hürden:
Mathematisches Vorwissen notwendig
Domainkonstruktion kann schwierig sein
Meist nur für kleines Fragment einer Programmiersprache
Grundlagen der Programmierung 2
- 4 -
Transformations-Semantik
Vorgehen zur Definition der Semantik eines Programms P ,
wenn die Semantik für Kernsprachen-Programme bereits definiert ist
•
•
Transformiere P → . . . → P 0 (in Kernsprache)
Nehme die Semantik von P 0.
Semantik von Haskell nutzt dieses Prinzip
(zB Pattern, List Comprehensions)
Vorteile:
Vereinfacht Semantik-Definition
Analog zur Arbeitsweise von Compilern
Grundlagen der Programmierung 2
- 5 -
Axiomatische Semantik
Beschreibung der Programmkonstrukte und Eigenschaften von Programmen mittels logischer Axiome
Herleiten von Programmeigenschaften durch logisches Schließen
Z.B. in Prädikatenlogik:
Für alle Eingaben n von natürlichen Zahlen
liefert quadrat n das Ergebnis n2. Als Formel:
∀n : quadrat(n) = n2
Grundlagen der Programmierung 2
- 6 -
Axiomatische Semantik
Hoare-Logik:
{x > 2} x := x+1 {x > 3}
Vorbedingung
Nachbedingung
Programmbefehl
Grundlagen der Programmierung 2
- 7 -
Auswertung
Programmen:
von
einfachen
Haskell-
Ziel: operationale Semantik von Haskell
• formal saubere Definition der Auswertung
• auch für Funktionen höherer Ordnung
• Unabhängigkeit von Compilern
• Unabhängigkeit vom Rechnertyp (Portabilität)
Grundlagen der Programmierung 2
- 8 -
Einfache Haskell-Programme
Definition:
Basiswert ist entweder eine Zahl,
ein Zeichen oder True,False.
Einfache Haskell-Programme: dürfen benutzen:
•
•
•
•
Basiswerte und entsprechende vordefinierte Operatoren
Funktionsdefinitionen
if-then-else
Anwendung von Funktionen auf Argumente
Grundlagen der Programmierung 2
- 9 -
Einfache Haskell-Programme (2)
Definition:
Ein (einfaches) Haskell-Programm besteht aus:
• Menge von Funktionsdefinitionen; entsprechend obiger Beschränkungen
• Ausdruck (main) vom Typ eines Basiswertes.
Wert des Programms = Wert von main
Beispiel
quadrat x = x * x
kubik x
= x * x * x
w
= 2
main
= if w >= 0 then quadrat w else kubik w
Grundlagen der Programmierung 2
- 10 -
Berechnung und Auswertung
Prinzip der Berechnung für einfache Haskell-Programme
Folge von Transformationen
Auswertung = von main
bis ein Basiswert erreicht ist
main → t1 → t2 → . . . → tn → . . .
Es gibt drei Fälle:
1. Die Folge endet mit einem Basiswert
2. Die Folge endet, aber nicht mit einem Basiswert
(kommt nicht vor wegen des Typsystems)
3.
Die Folge endet nicht
Bei 2. und 3.: Wert undefiniert.
Grundlagen der Programmierung 2
- 11 -
Auswertung
Einfache Haskell-Programm haben drei verschiedene
Arten von Auswertungsschritten
1. Definitionseinsetzung (δ-Reduktion)
2. Arithmetische Auswertung
3. Auswertung von Fallunterscheidungen
Grundlagen der Programmierung 2
- 12 -
Satz von Church und Rosser
Satz (Church-Rosser 1) Sei P ein einfaches Haskell-Programm,
R1, R2 zwei verschiedene Reduktionsfolgen für main
mit jeweiligen Resultat-Basiswerten e1 bzw. e2
dann sind diese Basiswerte gleich, d.h. e1 = e2
Grundlagen der Programmierung 2
- 13 -
Werte von Programmen
Definition: Sei P ein einfaches Haskell-Programm und
main von numerischem oder Booleschem Typ.
Der Wert des Programms P ist:
e
wenn es eine terminierende Reduktionsfolge, ausgehend
von main gibt, die mit dem Basiswert e endet,
⊥ ( undefiniert )
wenn es keine mit einem Basiswert terminierende Reduktionsfolge ausgehend von main gibt.
Aus dem Satz von Church-Rosser-1 folgt:
Ein einfaches Haskell-Programm
hat einen eindeutig definierten Wert
unabhängig von der Art der Auswertung
Grundlagen der Programmierung 2
- 14 -
Satz 2 von Church und Rosser
SATZ (Church-Rosser-2) Sei P ein einfaches Haskell-Programm.
Wenn es irgendeine Reduktionsfolge für main gibt,
die mit einem Basiswert e terminiert,
dann terminiert auch die normale Reihenfolge der Auswertung von main
und liefert als Basiswert (Resultat) genau e.
Die normale Reihenfolge ist ausreichend zur Auswertung
Haskell benutzt normale Reihenfolge der Auswertung
Grundlagen der Programmierung 2
- 15 -
Gegenbeispiel zu C.R. 2 bei applikativ
Church-Rosser-2 gilt nicht für die applikative Reihenfolge:
nt x
= nt x
proj x y = x
main
= proj
0
(nt 1)
Applikative Reihenfolge für main terminiert nicht:
(nt 1) → (nt 1) → (nt 1) → . . . . . .
Deshalb:
proj 0 (nt 1) → proj 0 (nt 1) → . . . . . .
Die normale Reihenfolge liefert sofort 0.
Grundlagen der Programmierung 2
- 16 -
Programmtransformationen
Optimierung: Programm P wird zur Compilezeit mittels
Transformationen in ein anderes Programm P 0 umgewandelt,
welches weniger Ressourcen benötigt, aber den gleichen Effekt hat.
gleicher Effekt“ (∼) :
”
• ∼ ist mithilfe der operationalen Semantik definierbar
• Äquivalenzrelation ∼ auf Programmen
und Funktionen vom gleichen Typ
• Verschiedene Zahlen und Boolesche Werte
sind verschieden unter ∼.
Grundlagen der Programmierung 2
- 17 -
Programmtransformationen
Aussage:
Für einfache Haskellprogramme gilt:
Alle bisher betrachteten Reduktionen, auch deren Umkehrung, sind
auch als Compilezeit-Transformationen verwendbar.
D.h. Wenn P → P 0 mit einer Reduktion, dann gilt auch P ∼ P 0.
Begründung: 1. Satz von Church-Rosser:
Wenn P zu e auswertet und P → P 0 ist eine Transformation,
dann wertet auch P 0 zu e aus.
Grundlagen der Programmierung 2
- 18 -
Programmtransformationen
[]
++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)
Beispiel:
→
→
=⇒
[a] ++ as
a:([] ++ as)
a:as
[x]++xs
Grundlagen der Programmierung 2
kann zu
Reduktion für append, da [a] = a:[]
Transformation mittels append
x:xs
vereinfacht werden
- 19 -
Programmtransformationen
Bei Beschränkung auf applikativer Reihenfolge der Auswertung
sowie in Programmiersprachen, die die appl. Reihenfolge verwenden,
sind diese Transformationen nicht korrekt,
Beispiel: Ein terminierendes Programm
kann zu einem nichtterminierenden werden:
meinif b x y = if b then x else y
main = meinf True True bot
Nach der Transformation:
main =
if True then True else bot
D.h. auch: ein nichtterminierendes Programm
kann zu einem terminierenden werden.
Grundlagen der Programmierung 2
- 20 -
Church-Rosser-Sätze auch für Konstruktoren
Verallgemeinerter Wert statt Basiswert; auch Listen sind Werte:
Ein (verallgemeinerter) Wert ist entweder
1. ein Basiswert
d.h. eine Zahl oder einer der
Wahrheitswerte True, False,
oder
2. eine Applikation (c t1 . . . tn), wobei c ein Konstruktor ist
mit der Stelligkeit n
Beispiele:
[1,2,3,4]
1: (map quadrat [2,3,4])
Beachte:
verallgemeinerte Werte können unausgewertete
Unterausdrücke haben
Grundlagen der Programmierung 2
- 21 -
Church-Rosser-Sätze
mit Listen
für
Haskell-Programme
Satz(Church-Rosser-1) Sei P ein Haskell-Programm,
wobei Konstruktoren und case erlaubt sind, und
main den Typ eines verallgemeinerten Basiswertes hat.
Wenn zwei verschiedene Reduktionsfolgen jeweils
verallgemeinerte Werte e1 bzw. e2 ergeben,
dann gibt es einen weiteren verallgemeinerten Wert e3,
so dass sowohl e1 als auch e2 zu e3 (in keinem, einem oder mehreren
Schritten) reduziert werden können:
|
||
|
||
||
|
||
||
|
|
|~ |
P BBB
BB
BB
BB
BB
BB
BB
BB
∗
e1B
B
B
B
∗
B
B
B
B
B!
e3
Grundlagen der Programmierung 2
∗
e2
}|
|
|
|
|
|
|
|
|
∗
- 22 -
Church-Rosser-Sätze; Beispiele
Beispiel:
Der Ausdruck [3+4,5+6] ist schon ein Wert,
auf zwei Arten reduzierbar:
[3 +n 4, 5 +
6]
PP
PPP
PPP
PPP
PPP
PPP
PPP
PPP
PPP
PP(
nn
nnn
n
n
nnn
nnn
n
n
nnn
nnn
n
n
nw nn
[7, 5 + 6]
P
PP
PP
PP
PP
PP
PP
P'
[3n+ 4, 11]
n
n n
n
n
n n
n
n
n n
n
nv
[7, 11]
Grundlagen der Programmierung 2
- 23 -
Church-Rosser-Sätze; Beispiele
Beachte: Normalform muss nicht existieren
Beispiel
(3 + 4)i : ((5 + 6)
: [1..]
UU
iiii
iiii
i
i
i
iiii
iiii
i
i
i
iiii
iiii
i
i
i
i
t iii
i
7 : ((5 + 6) :UU[1..]
UUUU
UUUU
UUUU
UUUU
UUUU
UUUU
UUUU
UUUU
UUUU
U*
UUUU
UUUU
UUUU
UUUU
UUUU
UUUU
UUUU
UUUU
UUUU
UU*
(3 + i4) : (11 : [1..])
iii
iiii
i
i
i
iiii
iiii
i
i
i
iiii
iiii
i
i
i
iii
it iii
7 : 11 : [1..]
Grundlagen der Programmierung 2
- 24 -
Church-Rosser-Satz 2
verallgemeinerte
Werte e1, e
e1>
>
>
>
>
>
>
>
>
>
P
>
>
bel. Auswertung
∃
n
A orm
us
w ale
er R
tu .
ng -
Satz (Church-Rosser-2) Sei P ein let-freies Haskell-Programm.
Wenn irgendeine Reduktionsfolge main zu einem verallg. Wert e reduziert,
dann terminiert auch die normale Reihenfolge der Auswertung von main
mit einem verallg. Wert e1,
und e1 ist reduzierbar zu e.
>
> e
Grundlagen der Programmierung 2
- 25 -
Church-Rosser-Satz 2. Beispiel
[3 + 4]++[5 + 6]
.
sw
e
u
A
al
m
r
no
[3 + 4, 5 + 6]
[3 + 4, 11]
[3 + 4, 5 + 6] ist ein verallgemeinerter Wert
Grundlagen der Programmierung 2
- 26 -
Haskell mit rekursivem let
Church-Rosser-Sätze gelten nicht in vollem Haskell
Grund:
rekursives let.
Church-Rosser-Sätze sind zu syntaktisch!
Grundlagen der Programmierung 2
- 27 -
Church-Rosser-Sätze: Verallgemeinerung
Notwendig: Konzept der Verhaltensgleichheit ∼ von Ausdrücken:
•
•
verschiedene Basiswerte a, b sind nicht verhaltensgleich:
a 6= b ⇒ a 6∼ b
man kann Gleiches durch Gleiches ersetzen
a ∼ b ⇒ P [a] ∼ P [b]
Nachzuweisen ist dann:
• Reduktionen (bzw. Optimierungen)
erhalten die Verhaltensgleichheit:
s→t⇒s∼t
Grundlagen der Programmierung 2
- 28 -
Induktion und Co-Induktion zum Nachweis der
Gleichheit von Ausdrücken
Induktionsschema für endliche Listen xs:
1.
2.
Zeige die Behauptung für xs = [].
Zeige, dass die Behauptung für x : xs gilt
unter der Annahme, dass sie für xs gilt.
Grundlagen der Programmierung 2
- 29 -
Co-Induktion für Listen
Co-Induktionsschema für endliche und unendliche Listen xs:
1.
2.
3.
Zeige die Behauptung für xs = [].
Zeige die Behauptung für xs = ⊥.
Zeige, dass die Behauptung für x : xs gilt
unter der Annahme, dass sie für xs gilt.
Grundlagen der Programmierung 2
- 30 -
Induktion für endliche Listen. Beispiel
Zeige:
length(xs ++ ys) = length(xs) + length(ys)
für alle endlichen Listen xs,ys
Basisfall:
length([] ++ ys) = length(ys),
und length([]) + length(ys) = length(ys)
Grundlagen der Programmierung 2
- 31 -
Induktion. Beispiel
Zeige:
length(xs ++ ys) = length(xs) + length(ys)
für alle endlichen Listen xs,ys
Induktionsfall: xs ist eine Liste der Länge n + 1.
Auswertung beider Seiten, wobei xs = x:xs’.
length(xs ++ ys) → length((x:xs’ ++ ys)
→ length((x:(xs’ ++ ys)) →
1+ length((xs’ ++ ys)) = 1+ length(xs’)+ length(ys)).
length(xs) + length(ys)
=
1+ length(xs’) + length(ys).
Grundlagen der Programmierung 2
→
length(x:xs’) + length(ys)
- 32 -
Herunterladen