Praktische Informatik I - Fachbereich Mathematik und Informatik

Werbung
Berechenbarkeit,
Beweisbarkeit
Paradigmen
Inhalt
1.
Prolog
n
DataLog und Prolog
n
Variablen und Terme
n
Backtracking
n
Turing-Vollständigkeit
2.
Der Lambda-Kalkül
n
Lambda-Terme
n
Gebundene Variablen
n
DeBruijn Darstellung
n
Turing-Vollständigkeit
3.
Kombinatorische Logik
n
Kombinatoren
n
Kompilation Lambda-Kalkül
n
Äquivalenz
4.
Objektkalkül
n
Featherweight Java
n
Bool in FJ
n
N in FJ
n
Test
© H. Peter Gumm, Philipps-Universität Marburg
Prolog
¨
¨
Logische Programmiersprache
Programme sind Axiome
(Fakten) und Regeln
n
n
Von rechts nach links zu lesen
von links nach rechts: ( = „falls“
strasseNass ( schneit.
gefaehrlich ( dunkel, friert.
gefaehrlich ( strasseNass.
friert ( schneit.
schneit.
dunkel.
¨
Berechnung ist logische Inferenz
n
Programmaufruf z.B.:
gefährlich.
n
Antwort: yes.
© H. Peter Gumm, Philipps-Universität Marburg
Horn-Klauseln
•
•
Prolog Programme sind Listen von Horn
Klauseln.
p :- q1, … , qn .
Sprechweise:
„p falls q1 und … und qn“.
Spezialfall Fakt:
p.
Ein Goal:
:- g1, … , gn .
•
Logische Interpretation :
p ( q1 Æ … Æ qn.
•
Spezialfall: Fakt:
p.
•
Eine Zielklausel
False ( g1Æ … Ægn
•
© H. Peter Gumm, Philipps-Universität Marburg
Berechnung in Prolog
Aufruf durch Goalklausel:
•
g1,…,gn
Wähle erstes goal g1
Finde passende Programmklausel:
•
p :- q1 , …, qn. mit p ¼ g1
Ersetze g1 durch q1 , …, qn.
Wiederhole, bis goal leer.
•
Beispiel Goal:
:- gefaehrlich.
•
mit Programmklausel
gefaehrlich :- dunkel, friert.
•
ergibt neues goal
:- dunkel, friert.
•
mit Fakt
dunkel.
•
ergibt
:- friert.
•
mit Programmklausel
friert :- schneit
•
ergibt
:- schneit.
•
mit Fakt
schneit.
•
ergibt leeres goal : yes.
© H. Peter Gumm, Philipps-Universität Marburg
Werte in PureProlog
•
•
•
Wir betrachten ein extrem abgespecktes Prolog
Ziel: zeige, dass Turing-vollständig
Terme
• Atome
•
•
•
Variablen
•
•
•
beginnen mit Kleinbuchstaben
a, b, otto, eva, r2D2
beginnen mit Großbuchstaben
X, Y, Rest, T1
f(t1,…,tn) -- benutzerdefiniert
•
•
f Funktionsname, eigentlich Konstruktoren
t1,…,tn Terme
© H. Peter Gumm, Philipps-Universität Marburg
Variablen in Prolog
•
Syntaktisch:
• Beginnen mit Grossbuchstaben
•
•
Semantisch
• matchen (genauer: unifizieren) mit
•
•
•
•
X, Y, T1, Clausel1, TestWert
Werten
anderen Variablen
(gemischten) Termen
Beispiele
• X matcht mit 17.
•
•
f(X, Y, Z ) matcht mit f(1, 3, g( 2,4))
•
•
Ergebnis: { X a 1, Y a 3, Z a g(2,4) }
Weitere Lösung …
f(X, 17, 3, g(42)) matcht mit f(3, Y, X, g(Z))
•
•
Ergebnis: { X a 17 }
Ergebnis: { X a 3, Y a 17, Z a 42}
h(X, 17, 3 ) matcht nicht mit h( 4, Y, X)
•
Konflikt: X a 4, X a 3
© H. Peter Gumm, Philipps-Universität Marburg
Relationen in Prolog
•
Statt einfachen Aussagen kann Prolog
auch Relationen benutzen
•
Fakten mit einstelligen Relationen:
weiblich(anna).
weiblich(eva).
•
mit zweistelligen Relationen
vater(otto,eva).
vater(ernst,hans).
vater(otto,anna).
•
Programmklauseln mit Relationen
tochter(X,Y) :-
vater(Y,X),
weiblich(X).
schwester(X,Y) :- tochter(X,Z),
tochter(Y,Z).
•
Goals
:- schwester(anna,X).
Es gibt eine weitere Lösung. Welche ?
© H. Peter Gumm, Philipps-Universität Marburg
Variablen in Relationen
• sommer unterrichtet graphik
• …
• jeder (X) unterrichtet
praktische
• einstein unterrichtet alles (X)
• frageZu(G,Nr)
• falls es ein Prof gibt,
• mit
unterrichtet(Prof,G),
• und telefon(P,Nr).
© H. Peter Gumm, Philipps-Universität Marburg
Werte in PureProlog
•
•
•
Wir betrachten ein extrem abgespecktes Prolog
Ziel: zeige, dass Turing-vollständig
Terme
• Atome
•
•
•
Variablen
•
•
•
beginnen mit Kleinbuchstaben
a, b, otto, eva, r2D2
beginnen mit Großbuchstaben
X, Y, Rest, T1
f(t1,…,tn)
•
•
-- benutzerdefiniert
f Funktionsname, eigentlich Konstruktor
t1,…,tn Terme
© H. Peter Gumm, Philipps-Universität Marburg
Rechnen in PureProlog
n
n
Wie repräsentieren wir Z ?
¨ Durch Atom nix und Terme
¨ nix, s(nix), s(s(nix)), …
Wie stellen wir Funktionen dar
¨ f: N ! N durch k+1-stellige
Relation rf µ Nk+1:
n
n
f(n1,…,nk)=y , rf(n1,…,nk,y)
Beispiele:
¨
Nachfolgerfunktion
n
¨
succ(X,s(X))
2+3=5 in Pure Prolog
Addition
n
n
add(nix,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
© H. Peter Gumm, Philipps-Universität Marburg
Logische Semantik
8 X. succ(X) = s(X).
8 Y. nix +Y = Y
8 X,Y,Z. X+Y=Z ) s(X)+Y=s(Z)
Aus diesen Voraussetzungen folgt:
8 s(s(nix))+s(s(s(nix))) =
s(s(s(s(s(nix)))))
5
© H. Peter Gumm, Philipps-Universität Marburg
Prolog Berechnung
1.
2.
n
add(nix,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
Goal:
add(s(s(nix)),s(s(s(nix))),U).
% aktuelles goal
¨
add(s(X),
Y,
s(Z)) :- add(X,Y,Z). % Regel (2.)
¨
¨
Ergebnis de matchens:
{ X a s(nix), Y a s(s(s(nix))), U a s(Z) }
angewendet auf body von 2. entsteht neues goal:
n
n
d.h.
add(X,Y,Z) { X a s(nix), Y a s(s(s(nix))), U a s(Z) }
add(s(nix),s(s(s(nix))), Z) { U a s(Z) }
nochmal passt Regel 2.
…
… führt schliesslich zu
n
add(nix,s(s(s(s(s(nix))))), Z) { X a s(nix), Y a s(s(s(nix))), U a s(Z) }
n
jetzt passt Regel 1:
n
add(nix,X, X)
n
mit X = s(s(s(s(s(nix))))) = Z
n
also U = s(Z) = s(s(s(s(s(nix)))))
¨
Lösung also: U = s(z) :- s(s(s(s(s(nix))))
© H. Peter Gumm, Philipps-Universität Marburg
Listen in Prolog
•
[] leere Liste
•
[H | R ] Liste mit Kopf H und Rest R
•
Kurzschreibweisen:
H
R
[ 3 ] kurz für [ 3 | [] ]
[ 2, 3 ] kurz für
[2 | [ 3] ] = [ 2| [ 3 | [] ] ]
[ r, 2, X, 3] kurz für
[ r | [ 2,X,3]] =
= …
= [r | [2 | [X | [ 3 | []]]]]
r
2
X
3
© H. Peter Gumm, Philipps-Universität Marburg
Funktionen – funktionale Relationen
•
n-stellige Funktionen durch (n+1)stellige Prädikate
p(x_1,…,x_n,y)
statt
f(x_1,…,x_n) = y
•
Beispiele:
• conc([r,2],[d,2],[r,2,d,2])
statt conc([r,2],[d,2])= [r,2,d,2]
•
rev([r,3,“otto“],X)
statt X=rev[r,3,“otto“]
•
rekursive Aufrufe erlaubt
•
Abarbeiten der Programm-klauseln
der Reihe nach
•
Bearbeitung der Goal-teile von
links nach rechts
© H. Peter Gumm, Philipps-Universität Marburg
Arithmetische Operationen
t is e
linkes Argument:
ein Term t
meistens eine Variable
rechtes Argument:
ein arithmetischer Ausdruck e
Semantik
berechnet arithmetischen Ausdruck
versucht, Ergebnis mit dem Term zu matchen
Beispiele:
X is 2+3
berechnet 2+3 und matcht mit X
0 is 56088 mod 123
wahr, falls 56088 mod 123 = 0, false sonst
Y = X*X
wahr falls zum Zeitpunkt der Berechnung
X einen Zahlenwert hat
dessen Quadrat Y matcht.
© H. Peter Gumm, Philipps-Universität Marburg
Benutzerdefinierte Terme
Datenwerte bisher
•
Atome, Strings, Listen
Eigene Datenwerte einführbar
•
müssen nicht definiert werden.
•
Syntaktisch wie Relationen
•
•
f(t1,…,tn)
¨ f Funktionszeichen
¨ ti Terme
stehen aber dort wo Wert verlangt ist
Beispiele:
•
Paare
¨ paar(2,3), paar(7,-19), paar(2,paar(X,3))
•
Bäume
¨ baum(‘*‘baum(‘+‘,blatt(5),
¨
blatt(7)),
¨
blatt(3))
•
Selbstgebaute Zahlen
n
nix, s(nix), s(s(nix)), s(s(X)), …
© H. Peter Gumm, Philipps-Universität Marburg
Seiteneffekte
•
Bearbeitung der Goal-Bestandteile
von
links nach rechts
•
•
wenn nicht >= 10
backtrack zur
nächsten nicht
untersuchten
Alternative
:- write(‘Hallo‘), write(‘ Welt‘).
Programmklauseln werden der Reihe
nach ausprobiert
•
Wenn notwendig: Backtracking
weitere Lösung vorhanden
© H. Peter Gumm, Philipps-Universität Marburg
Der Cut
•
Dient dazu, Backtracking
abzuschneiden
• kann man verwenden, um
Negation zu implementieren.
•
p :- q1,…,qk, !, qk+1,…,qn.
•
commit
test
Wenn bei der Berechnung von p die
Prämissen q1,…,qk erfolgreich
getestet wurden, wird keine weitere
Klausel für p mehr berücksichtigt.
© H. Peter Gumm, Philipps-Universität Marburg
Prolog ist Turing-vollständig
Reines Prolog genügt:
n
n
n
n
ohne Cut
ohne Zahlen
¨ Keine arithmetische Berechnung
keine Strings
¨ Strings sind ohnehin nur Listen von Zeichen
wohl aber Terme
¨ Listen sind nur syntaktischer Zucker für
n
n
¨
Zahlen kann man einführen mit
n
n
n
einstelliges Fkt.Zeichen []
zweistelliges Fkt.Zeichen [ X| Y] bzw. ‘.‘(X,Y)
nullstelligem FktZeichen o
einstelligem FktZeichen s(X)
Zwei Methoden, Turing-Vollständigkeit zu zeigen:
1.
2.
wir zeigen, dass jede rekursive Funktion in Prolog programmiert werden kann
wir implementieren eine Turingmaschine
© H. Peter Gumm, Philipps-Universität Marburg
Einfache Rekursive Funktionen
%% Natürliche Zahlen: o, s(o), s(s(o)), ...
n
% Addition
add(o,Y,Y).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
n
% Multiplikation
mult(o,Y,o).
mult(s(X),Y,Z) :- mult(X,Y,U),add(U,Y,Z).
n
% Fakultät
fakt(o,s(o)).
fakt(s(X),Z) :- fakt(X,U), mult(s(X),U,Z).
n
%Fibonacci
fib(N,Z) :- fibo(N,o,s(o),Z).
fibo(o,Prev,Last,Last).
fibo(s(X),Prev,Last,Z) :- add(Prev,Last,Sum), fibo(X,Last,Sum,Z).
© H. Peter Gumm, Philipps-Universität Marburg
Rekursive Fkt. in PureProlog
%% Natürliche Zahlen: o, s(o), s(s(o)), ...
% Konstante Funktion 0,
f(X1,…,Xn,o).
% i-te Projektion:
pi(X1,...,Xn,Xi).
% Nachfolger
succ(X,s(X)).
% Komposition:
pfi(X1,...,Xn,Z1) implementiere fi : Nn... , N ! N, für i=1...k
pg(Y1,...,Yk,Z) implementiere g : Nk ! N, dann implementiert
p(X1,...,Xn,W) :pf1(X1,...,Xn,Z1),
... ,
pfk(X1,...,Xn,Zk),
pg(Z1,...,Zk,W).
die Komposition g(f1(x1,…,xn),…,fk(x1,…,xn)) : Nn ! N.
© H. Peter Gumm, Philipps-Universität Marburg
Rekursive Fkt. in PureProlog
% Primitive Rekursion
pg(X1,...,Xn,Z) implementiere g:N,...,N --> N
ph(X1,...,Xn+1,Z) implementiere h : N,...,N,N --> N
% dann implementieren wir die aus g und h prim. rekursiv definierte Funktion f:
pf(o,X1,...,Xn, Z)
:- pg(X1,...,Xn,Z).
pf(s(X),X1,...,Xn, Z) :- pf(X,X1,...,Xn, Z1), ph(X,X1,...,Xn,Z1,Z).
% mu-Rekursion
% Sei p(X0,X1,...,Xn) ein p.r. Prädikat. Dann berechnen wir µk.P(k,X1,...,Xn) durch:
mu(X1,..,Xn,Y) :- min(o,X1,...,Xn,Y).
min(K,X1,...,Xn,K)
min(K,X1,...,Xn,V)
:- p(K,X1,...,Xn).
:- min(s(K),X1,...,Xn,V).
© H. Peter Gumm, Philipps-Universität Marburg
Beispiel für µx.p
Suche kleinstes
X mit
2*(x*x+X+1)+1=X3
X:=0;
while ( not pred(X) )
X:=s(X);
Y := X;
© H. Peter Gumm, Philipps-Universität Marburg
Eine Turing-Maschine in Prolog
Turing(+Chars,-Chars)
Band repräsentiert durch
zwei Listen
[t,u,r,i,n,g,t,a,p,e]
mit Kopf auf ‘ t‘
repräsentiert durch
das Paar
[g,n,i,r,u,t]
[t,a,p,e]
rule(q,c,q‘,c‘,move)
repräsentiert
die Turingtafel
= das Programm
% Band durch zwei Stacks repräsentiert: LS - linke Seite, teil links des Head
% RS - revers(rechte Seite). Rs=[Sym|Rest] wobei Sym das Zeichen unter dem Kopf
turing(Tape0, Tape) :perform(q0, [], Ls, Tape0, Rs),
% anfangs LS=[], RS=Tape0
reverse(Ls, Ls1),
% wenn man RS umdreht
append(Ls1, Rs, Tape).
% und an LS anhängt,
% ergibt sich am Ende das Band
% ein Schritt
perform(qf, Ls, Ls, Rs, Rs) :- !.
% qf ist Haltezustand
perform(Q0, Ls0, Ls, Rs0, Rs) :% ein Schritt
readSymbol(Rs0, Sym, RsRest),
% RS0=[Sym|RsRest], ausser wenn Rs0=[]
rule(Q0, Sym, Q1, NewSym, Action),
% Lese passende Regel
action(Action, Ls0, Ls1, [NewSym|RsRest], Rs1), % Sym üb.schreiben und bewegen
perform(Q1, Ls1, Ls, Rs1, Rs).
% und wieder von vorne
readSymbol([], b, []).
readSymbol([Sym|Rs], Sym, Rs).
% Am rechten Bandende wird b=blank gelesen
% ansonsten nächstes Zeichen
action(left, Ls0, Ls, Rs0, Rs) :- left(Ls0, Ls, Rs0, Rs).
action(stay, Ls, Ls, Rs, Rs).
% donothing
action(right, Ls0, [Sym|Ls0], [Sym|Rs], Rs). % unter dem Kopf ist jetzt ein Zeichen !
% notfalls wurde beim Lesen ein b angebracht.
left([], [], Rs0, [b|Rs0]).
% am linken Rand: neues b ... und nach lnks
left([L|Ls], Ls, Rs, [L|Rs]).
% klar
© H. Peter Gumm, Philipps-Universität Marburg
Die TM in Betrieb
n
Zwei Strichzahlen
werden addiert
n
llll + lll = lllllll
© H. Peter Gumm, Philipps-Universität Marburg
Inhalt
1.
Prolog
n
DataLog und Prolog
n
Variablen und Terme
n
Backtracking
n
Turing-Vollständigkeit
2.
Der Lambda-Kalkül
n
Lambda-Terme
n
Gebundene Variablen
n
DeBruijn Darstellung
n
Turing-Vollständigkeit
3.
Kombinatorische Logik
n
Kombinatoren
n
Kompilation Lambda-Kalkül
n
Äquivalenz
4.
Objektkalkül
n
Featherweight Java
n
Bool in FJ
n
N in FJ
n
Test
© H. Peter Gumm, Philipps-Universität Marburg
Funktionsdefinition
Eine typische Funktionsdefinition in einer Programmiersprache:
double(x) = x+x;
Bedeutung:
double ist die Funktion, die einem x zuordnet x+x.
Schreibweise:
double : x |→ x+x
Church verwendet stattdessen das Zeichen λ :
double = λ x. x+x
Parameter
Parameter
Körper
Körper
© H. Peter Gumm, Philipps-Universität Marburg
Mathematische Notation
x a expr(x)
λ x. x * x
x
λ x. x
x a x
a x * x
λ (x, y). ((λ x. x * x) x) + (λ x. x * x) y))
(x, y) a ((x a x * x) x) + ( x a x * x) y))
n
Meist gibt man dem Kind einen Namen und einen Typ:
sqr: N ! N
x a x * x
© H. Peter Gumm, Philipps-Universität Marburg
Das Gleiche im Lambda-Kalkül
n
Namenlos
λ x . expr(x)
„Die Funktion, die einem x zuordnet: expr(x)“
λ x. x * x
Die Quadrierfunktion
λ (x, y). ((λ x. x * x) x) + (λ x. x * x)y))
Die Quadratsumme
λ x. x
Die Identitätsfunktion
© H. Peter Gumm, Philipps-Universität Marburg
Abstraktion
Durch Abstraktion entstehen Funktionen. Eine vormals globale
Variable kann zum Parameter werden.
Ausdruck e:
Abstraktion
x+x
λ x. x+x
Die Funktion, die ihr
Argument verdoppelt
x+y
λ x. x + y
Die Funktion, die y zu
ihrem Argument addiert.
λ x. x + y
λ y. λ x. x + y
Die Funktion, welche
einer Zahl y diejenige
Funktion zuordnet, welche
ihrem Argument x den
Wert x+y zuordnet.
y ist global/frei
© H. Peter Gumm, Philipps-Universität Marburg
Abstraktion = Funktionsbildung
n
Wenn E ein λ-Term ist und x eine Variable,
dann ist λx.E ein λ-Term
bvar
¨
¨
n
body
x ist die gebundene Variable (bound variable)
E ist der Rumpf (body)
λ x.E soll die Funktion bezeichnen, die
¨
auf ein Argument E‘ angewendet werden kann,
n
¨
als Applikation ( (λ x. E) E‘ )
mit Resultat E[E‘/x]
n
n
Substitution von x durch E‘ in E (genaue Definition später)
E wobei jedes (freie) x in E durch E‘ ersetzt wurde.
(falls kein Namenskonflikt auftritt)
© H. Peter Gumm, Philipps-Universität Marburg
Funktionen mit mehrere Argumenten
Moses Schönfinkel: Wenn man Funktionen als Argumente erlaubt, kann
man man auf mehrstellige Funktionen verzichten.
Eine zweistellige Funktion
f : A£B → C
kann ersetzt werden durch die Funktion
wobei
f‘ : A → [B → C]
f‘ = λ a . λ b. f(a,b)
bzw.
Die Analogie zur Logik ist kein Zufall:
(A ∧ B) ⇒ C
ist äquivalent zu
A ⇒ (B ⇒ C)
f(a,b) = f‘(a)(b).
Auch die Anzahlformel stimmt noch
| A´ B → C | = |C||A´B|
= C|A|*|B|
= (C|B|)|A|
= | A → (B → C) |
© H. Peter Gumm, Philipps-Universität Marburg
Funktionsapplikation
Funktionsdefinitionen sind nutzlos, wenn man die Funktion nicht auch auf
ein Argument anwenden (applizieren) kann.
double 7 = ( λ x. x+x ) 7 = 7 + 7
Operator
Operand
Bei der Applikation nimmt der Parameter das Argument auf
und leitet es an die richtige Stelle im Körper weiter.
double = λ x. x+x
,
double(x) = x+x
© H. Peter Gumm, Philipps-Universität Marburg
Applikation = Anwendung
n
Wenn E1 und E2 λ-Ausdrücke sind, dann auch ( E1 E2 )
Operator
n
Operand
( E1 E2 ) bezeichnet das Ergebnis der Anwendung von E1 auf E2
¨
¨
¨
E1 dient hier als Funktion, E2 als Datum
Beides sind Lambda-Terme
Die Klammer ist i.A. nicht notwendig.
© H. Peter Gumm, Philipps-Universität Marburg
β-Reduktion
n
n
β-Reduktion ist Auswertung
¨ entspricht Makro-Auswertung in Programmiersprache
Im Körper einer Abstraktion wird textuell der Parameter
durch das Argument ersetzt.
Beispiele:
( λ x. x + x ) 7
( λ y. x + y ) 7
β
β
( ( λ y. λ x. x + y ) 7 ) 13
7+7
x+7
β
( λ x. x + 7 ) 13
β
13 + 7
© H. Peter Gumm, Philipps-Universität Marburg
Woraus bestehen λ-Terme
n
n
n
Variablen
¨ x,y,z, …
Abstraktionen
¨ λx.x*x,
λf.λx.f(f(x))
Applikationen
¨ f (3) , square (4), ((λx.x*x) x)
Applikationen
( λ (x, y). ((λ x. x * x) x) + (λ x. x * x) y)) (3.4)
Abstraktionen
© H. Peter Gumm, Philipps-Universität Marburg
Variablen
n
Variablen dienen als Platzhalter
¨
n
Es kommt nicht auf den Namen an, sondern
darauf, für welches Argument er steht
n
zins(betrag,satz) { return betrag*(1+satz) }
n
f(x,y){ return x*(1+y); }
n
λ x. x , λ y. y
n
λt.λ f. t, λx. λy. x
Variablen können an Werte gebunden sein
¨
in einer bestimmten Umgebung
n
n
die Anwendung f (3,4) bindet x a 3, y a 4
die Anwendung ( λt.λf. t ) ( 3 ) bindet t a 3
© H. Peter Gumm, Philipps-Universität Marburg
Lambda Kalkül– abstrakte Syntax
n
Sei V eine Menge von Variablen. Die Menge E aller λ-Ausdrücke (λTerme, λ−expressions) ist durch folgende Syntax definiert:
E
::=
V
| λ V. E
| E E
jede Variable ist ein λ-Term
Abstraktion
Applikation (Anwendung)
In der konkreten Syntax sind Klammern erlaubt.
Beispiele für λ-Terme:
x, λ x.x, ((λ x. x) y), λ x. λ y. x,
λ f. f (λ x. x x) (λ x. x x),
© H. Peter Gumm, Philipps-Universität Marburg
Mehrdeutigkeit
n
Die Grammatik ist nicht eindeutig
¨
Beispiel: λ x. x y hat zwei Ableitungen
:
n
Applikation λ x . x y
¨
¨
n
Abstraktion λ x . x y
¨
¨
¨
Operator : λ x.x
Operand : y
bvar : x
body : x y (selber eine Applikation)
Eindeutigkeit durch Klammerung
erreichbar
n
n
(λ x. x) y
λ x. (x y)
Beispiel:
( E1 E2 ) E3
λ f. ( ( f (λ x.(x x) ) ) ( λ x.(x x) ) )
=
λ f. ( f (λ x.(x x) ) ( λ x.(x x) ) )
=
λ f. f (λ x.(x x) ) ( λ x.(x x) )
=
λ f. f (λ x.x x ) ( λ x.x x )
=
λ f. f (λ x.x x ) λ x.x x
Applikation
Abstraktion
© H. Peter Gumm, Philipps-Universität Marburg
Weiteres Beispiel
n
Klammern sind notwendig, um festzulegen, wie L entstanden ist.
Beispiel: Der Ausdruck
λx. λy. x y λx.y
hätte viele Interpretationen:
1.
(λx.(λy.(x y))) (λx.y)
: Applikation mit Operator (λx.(λy.(x y)))
und Operand (λx.y)
2.
λx. (λy. x y) (λx.y)
: eine Abstraktion mit Körper (λy. x y) (λx.y)
3.
(λx. λy. x) (y λx.y)
: Applikation mit Operator (λx. λy. x)
und Operand (y λx.y)
4.
λx. λy. ((x y) (λx.y))
: eine Abstraktion mit Körper λy. ((x y) (λx.y))
© H. Peter Gumm, Philipps-Universität Marburg
Baumdarstellung ist eindeutig
n
n
λ-Terme sollte man sich eigentlich als Bäume vorstellen
¨ Es gibt λ-Knoten, Applikationsknoten und Variablen
Klammern nur nötig um diese eindimensional darzustellen
λ
= λ x. y z ≠
(λ x.y) z =
z
λ
x
y
z
x
λ
y
f
λ
λ f. f (λ x.x x ) λ x.x x =
λ
f
x
x
x
x
x
x
© H. Peter Gumm, Philipps-Universität Marburg
Vereinfachte Baumdarstellung
n
Lambda Knoten enthalten Parameternamen
f
x
x
y
z
λ x. y z
z
x
y
(λ x.y) z
f
x
x
x
Legende:
x
x
λ -Knoten mit bvar x
Applikationsknoten
y
x
λ f. f (λ x.x x ) (λ x.x x)
Variable y
© H. Peter Gumm, Philipps-Universität Marburg
Der reine Lambda Kalkül
nSyntax
L ::= v
|(LL)
| ( λ v. L )
Variablen
Applikation
v ::= x | y | z ....
Variablen
( (λx.(λy.(x y))) (λx.y) )
Abstraktion
x
x
y
y
Beispiele für Lambda-Ausdrücke
x, ( λx.x ) , (λx.(x y)),
((x y) x), ((λx.x) (λx.x)),
((λx.(λy.(x y)))(λx.y))
x
y
Baumdarstellung des λ−Ausdrucks
© H. Peter Gumm, Philipps-Universität Marburg
Klammerersparung Konvention
Äußere Klammern weglassen.
λ x. (x y) = (λ x. (x y))
x (λ x. x) = (x (λ x. x))
x
x
Applikationen links geklammert
y
x y z = (x y) z
(λ x.x) y (λ x.(λ y.x)) = (((λ x.x) y) (λx.(λ y. x)))
z
λ-Abstraktionen erstrecken sich
soweit nach rechts wie möglich
(λx.λy.x y)(λx.y) λx.y = ((λx.(λy.(x y)))(λx.y))
x
y
x
z
x
y
(λx. (λy. λz. x y z ) (y x)) λx. x = (( λx. (λy. (λz. ((x y) z) ) ) (y x)) (λx. x))
© H. Peter Gumm, Philipps-Universität Marburg
Freie und gebundene Variablen
n
Funktionsdefinitionen können gebundene ( = lokale) Variablen und
freie ( = globale) Variablen enthalten.
Abstand ( p ) = sqrt((x(p) - x(p0))2 + (y(p) - y(p0))2 )
Abstand = λ p . sqrt((x(p) - x(p0))2 + (y(p) - y(p0))2 )
p ist gebunden = lokal
p0 ist frei = global
p ist nur ein Platzhalter. Man könnte p auch umbenennen, z.B. in
q, r, .... nicht aber in p0 .
p0, sqrt, x und y sind Funktionskonstanten.
© H. Peter Gumm, Philipps-Universität Marburg
Freie und gebundene Variablen
Eine Variable v kann in einem Ausdruck L mehrfach vorkommen. Ein Vorkommen
von v in L heißt gebunden, falls es in einem Unterausdruck von L der Form ( λ v. P )
enthalten ist. Jedes andere Vorkommen von v
in L heißt frei.
x
Induktive Definition aller Variablen, die mindestens
an einer Stelle frei vorkommen:
FV(x) = { x }
FV( L1 L2 ) = FV(L1)[FV(L2)
FV( λx. L ) = FV(L) - { x }
y
x
y
y
frei
x
x
In dem λ-Term
( λ x. y x λ y. x z ) λ y. x
z
kommen x, y und z frei vor. Die linkesten zwei
Vorkommen von x werden von dem linken λx.
gebunden.
© H. Peter Gumm, Philipps-Universität Marburg
Term mit Bindung der Variablen
global
x
x
x
(λx. (λy. λz.x y z) y x) λx.x
y
z
y
x
z
x
y
© H. Peter Gumm, Philipps-Universität Marburg
Funktionsschachteln
n
In den meisten Sprachen
Blockschachtelung
¨
Variablen nur sichtbar:
n
n
n
¨
im definierenden Block
textuell nach der
definierenden Stelle
auch in geschachtelten
Blöcken
von einer Position sieht
man alle Variablen
n
n
die vorher und
im gleichen oder
einem umgebenden
Block definiert sind
{ int x;
{ int y;
int z;
x := x+z;
// o.k.
{ int z ;
int u ;
z := x+u; // o.k. z ist das innerste
x := x+v; // illegal v ist frei
}
{ int v;
z := u+v; // illegal v von hier nicht sichtbar
}
}
}
© H. Peter Gumm, Philipps-Universität Marburg
Schachtelung als Baum
n
Eine Variable muss auf einem Weg
zur Wurzel gefunden werden
¨ sonst frei – global
n
Beispiel: v frei
n
int x;
int x; int z;
x := x+z;
int z; int u;
z := x+u;
x := x+v;
int v;
z := u+v;
{ int x;
{ int y;
int z;
x := x+z;
{ int z ;
int u ;
z := x+u;
x := x+v;
}
{ int v;
z := u+v;
}
}
}
© H. Peter Gumm, Philipps-Universität Marburg
Intendierte Semantik
λ x. x
die Identitätsfunktion
(λ x, x) y
Identitätsfunktion angewendet auf y
λ x. λ y. y
angewendet auf ein Argument liefert
diese Funktion die Identitätsfunktion
λ x. λ y. x
angewendet auf ein Argument a liefert diese
Funktion als Ergebnis die konstante Funktion
mit Ergebnis a
x λ x. y
Wenn x eine Funktion ist, dann wird diese
angewendet auf die konstante Funktion
mit Ergebnis y
© H. Peter Gumm, Philipps-Universität Marburg
Syntaktische Ersetzung
Für beliebige Terme s definieren wir die Ersetzung einer Variablen
x durch einen Term t. Dabei werden nur freie Variablen ersetzt.
s {x/t}
ist der Term, der aus s entsteht, wenn man alle
freien Vorkommen von x durch t ersetzt. )*
Die Definition folgt dem syntaktischen Aufbau von λ-Termen:
1. s ist eine Variable v
a) v ≡ x : x { x/t } = t
b) v ≠ x : v { x/t } = v
λ-Syntax :
s ::= v
|(s s)
| ( λ v. s )
2. s = (s1 s2) eine Applikation:
(s1 s2) { x/t } = (s1 { x/t } s2 { x/t } )
3. s = λ v. s eine Abstraktion:
a) v ≡ x : (λ x. s) { x/t } = (λ x. s)
b) v ≠ x : (λ v. s) { x/t } = (λ v. s { x/t } )
)* Wir werden diese Ersetzungsrelation später noch durch eine bessere, s[x/t], ersetzen.
© H. Peter Gumm, Philipps-Universität Marburg
Syntaktische Transformationen: α
Wenn λ-Terme Funktionen darstellen sollen, dann kann es vorkommen,
daß verschiedene Terme die gleiche Funktion darstellen.
Grund: Gebundene Variable sind nur Platzhalter.
α:
α:
λ x. x
x ( λ x. x y )
λ y. y
=
beidesmal die Identitätsfunktion
=
x ( λ z. z y )
denn ( λ x. x y ) = ( λ z. z y )
≠
λ y. y y
hier wird das vormals freie
y versehentlich gebunden !
aber Vorsicht :
λ x. x y
© H. Peter Gumm, Philipps-Universität Marburg
Analogie zu anderen mathematischen Notationen
Gebundene Variablen tauchen auch in anderen Gebieten der
Mathematik auf. Man darf sie immer umbenennen, falls kein
Konflikt mit einer anderen Variablen auftaucht. Ein Konflikt
bedeutet, daß eine vormals freie Variable gebunden wird.
N
Σ
i=1
∀x.∃y. x < y
∫
z sin(x) y2 dx dy =
∫
aik =
=
N
Σ axk
x=1
≠
∀u.∃y. u < y
z sin(u) v2 du dv ≠
∫
N
Σ akk
k=1
≠
∀y.∃y. y < y
z sin(z) v2 dz dv ≠
∫
v sin(v) v2 dv dv
Man kann Konflikte vermeiden, wenn man bei jeder Umbenennung
„frische“ Variablen benutzt.
© H. Peter Gumm, Philipps-Universität Marburg
α−Äquivalenz
nZwei
Terme s und t heißen α-äquivalent, s =α t falls sie durch konfliktfreie Umbenennung von gebundenen Variablen ineinander übergeführt werden können.
Definition: s =α t folgt dem syntaktischen Aufbau von s:
1. s ist eine Variable v
v
=α
t
⇔
v ≡ t.
2. s = (s1 s2) eine Applikation:
(s1 s2)
=α
(t1 t2)
⇔
3. s = λ v. s eine Abstraktion:
λ x. s =α λ v. s {x/v}
Lemma :
=α
s1
=α
⇔
t1 und s2
=α
t2
x ≡ v oder v ∉ FV(s).
ist eine Äquivalenzrelation und es gilt für beliebige λ-Terme s,t,t‘:
t =α t‘
⇒ s{x/t} =α s{x/t‘}.
© H. Peter Gumm, Philipps-Universität Marburg
β-Reduktion
λ-Terme sollen Funktionen darstellen. Wird eine Abstraktion auf ein
Argument angewandt, dann wird die gebundene Variable im Körper durch das
Argument ersetzt. Dies kann man als Auswertung auffassen.
(λ x. x) t
(λ x. x y ) t
β
β
(λ x. λ z. x z ) (x y)
t
t y
β
λ z. (x y) z
Aber Vorsicht, das darf nicht passieren :
(λ x. λ y. x y ) (x y)
β
λ y. (x y) y
Die freie Variable y in (x y) wurde gebunden, weil sie zufällig genauso
heißt wie eine gebundene Variable in (λ x. λ y. x y ).
© H. Peter Gumm, Philipps-Universität Marburg
β-Reduktion
(λ x. s) t
Ein β-Redex ist ein Term der Gestalt
Ein β-Redex wird reduziert, indem jedes freie Vorkommen
des Parameters im Körper der Abstraktion durch das Argument
t ersetzt wird. Dabei darf keine freie Variable von t gebunden werden.
(λ x. s) t
β
s {x/t}
falls kein freies Vorkommen
einer in t freien Variablen in
s[x/t] gebunden wird.
Wir erweitern die Definition dahingehend, daß β-Reduktion auch
auf Teilterme angewendet werden kann:
β
s1 ! s‘1
β
(s1 s2) ! (s‘1 s2)
β
s2 !
s‘2
β
(s1 s2) ! (s1 s‘2)
β
s!
s‘
β
λ v. s ! λ v. s‘
© H. Peter Gumm, Philipps-Universität Marburg
Vorherige Umbenennung
Und was machen wir nun mit dem folgenden β-Redex ?
(λ x. λ y. x y ) (x y)
Lösung: Benenne zuerst die gebundenen Variablen um:
(λ x. λ y. x y ) (x y)
α
!
(λ x. λ z. x z ) (x y)
β
!
λ z. (x y) z
© H. Peter Gumm, Philipps-Universität Marburg
Sichere Substitution
Wir definieren nun einen Operator der sicheren Substitution,
um in einem Ausdruck s die freie Variable x durch t zu ersetzen.
s [ x/t ]
Die Definition folgt wieder dem syntaktischen Aufbau von λ-Termen:
1. s ist eine Variable v
a) v ≡ x : x [ x/t ] = t
b) v ≠ x : v [ x/t ] = v
2. s = (s1 s2) eine Applikation:
(s1 s2) [ x/t ] = (s1[ x/t ] s2 [ x/t ] )
λ-Syntax :
s ::= v
|(s s)
| ( λ v. s )
3. s = λ v. s eine Abstraktion:
a) v ≡ x : (λ x. s) [ x/t ] = (λ x. s)
b) v ≠ x und v nicht frei in t:
(λ v. s) [ x/t ] = (λ v. s [ x/t ] )
c) v ≠ x und v frei in t:
(λ v. s) [ x/t ] = (λ v‘. s [v/v‘][ x/ t ] )
wobei v‘ eine neue Variable ist.
© H. Peter Gumm, Philipps-Universität Marburg
Kongruenzrelationen
Auf der Menge aller λ-Terme wollen wir eine Gleichheitsrelation definieren. Sie soll
mindestens die Leibniz-Eigenschaften erfüllen:
Für alle Terme r, s, t:
1. s ≈ s
2. s ≈ t
⇒
(Reflexivität)
t ≈ s
3. r ≈ s , s ≈ t
⇒
4. s1 ≈ t1 , s2 ≈ t2
5. s ≈ t
⇒
(Symmetrie)
r ≈ t
⇒ (s1 s2) ≈
(Transitivität)
(t1 t2)
λv. s ≈ λv. t
Eine Relation, die die Bedingungen 1.-3- erfüllt, heißt Äquivalenzrelation.
Falls sie zusätzlich 4. und 5. erfüllt, heißt sie Kongruenzrelation.
Lemma: Eine Äquivalenzrelation R ist genau dann eine Kongruenzrelation,
wenn für je drei Terme s, t, t‘ und Variablen x gilt:
t R t‘
⇒ s {x/t} R s {x/t‘}.
© H. Peter Gumm, Philipps-Universität Marburg
αβ-Gleichheit
nWir
wollen Terme identifizieren, wenn sie α-gleich sind, oder wenn sie
durch eine β-Reduktion ineinander übergeführt werden können. Dadurch
entsteht zwangsläufig die folgende Definition:
=αβ
sei kleinste Kongruenzrelation die =α und
β
umfaßt.
Oft, aber nicht immer, wird bei einer β-Reduktion der Term vereinfacht,
wie folgendes Beispiel zeigt. Wir kürzen ab: ω := λ x.(x x) und rechnen:
ωω
β
( λ x. (x x) ) ω
β
ωω
β
...
Übung: Finden Sie einen Term, der bei jeder β-Reduktion echt größer wird.
© H. Peter Gumm, Philipps-Universität Marburg
Charakterisierung von =αβ
Lemma: Für zwei Terme s und t gilt
s =αβ t
s
⇔
es gibt λ-Terme e1, ... , en. mit
a) s ≡ e1
b) t ≡ en,
c) für jedes i ≤ n gilt
β
β
ei =α ei+1 oder ei
ei+1 oder ei+1
β
β
β
β
β
=α
β
ei.
t
β
β
=α
© H. Peter Gumm, Philipps-Universität Marburg
Extensionalität
Wir wollen λ-Terme nicht unterscheiden, wenn sie die gleichen Funktionen
beschreiben, d.h. wenn sie auf allen Argumenten den gleichen Wert liefern.
Wir müssen also insbesondere identifizieren:
λ x. t x
und
t
falls x nicht frei in t.
Beispiel:
y und λx . y x repräsentieren die gleiche Funktion, denn für jedes s gilt
( λx . y x) s =αβ y s. Ähnliches kann man für λx. (λy. y) x und λy. y sagen.
λ x. s x
η
s
falls x nicht frei in s
vorkommt
η-Redex
Nebenbedingung ist notwendig, wie das folgende Beispiel zeigt:
Setze s = λ y. x . Wäre λx. s x = s, dann würde folgen
(λx . (λ y. x) x ) z = (λ y. x) z , also
(λ y. z) z = x , also z = x.
© H. Peter Gumm, Philipps-Universität Marburg
Charakterisierung der Extensionalität
nDefiniere
=α ,
β
=αβη als kleinste Kongruenzrelation, die
η
und
umfaßt.
Lemma: Für zwei Terme s und t gilt
s =αβη t
⇔
es gibt λ-Terme e1, ... , en. mit
a) s ≡ e1 ,
b) t ≡ en,
c) für jedes i ≤ n gilt
β
β
ei =α ei+1 oder ei
ei+1 oder ei+1
oder ei
η
ei+1 oder ei+1
η
ei
ei
Das folgende Resultat berechtigt uns, von Extensionalität zu reden:
Lemma: =αβη ist die kleinste Kongruenzrelation, die =αβ umfaßt und
folgende Eigenschaft erfüllt:
Kommt die Variable x, nicht frei in s oder t vor, so gilt
s x =αβη t x
⇔
s = t.
Von jetzt ab verstehen wir „=„ immer als „=αβη“
© H. Peter Gumm, Philipps-Universität Marburg
Wie kann man herausfinden, ob s =αβη t
Um herauszufinden, ob s =αβη t gilt, müssen wir eine Kette wie
unten dargestellt finden. Wie können wir das bewerkstelligen ?
s
η
β
η
β
β
=α
β
t
β
η
=α
Am einfachsten wäre es, wenn wir sowohl s als auch t soweit wie möglich
reduzieren könnten bis wir auf den gleichen Term stoßen :
s
t
Die Pfeile stehen jetzt für α-,
β- oder η-Reduktionen.
© H. Peter Gumm, Philipps-Universität Marburg
Normalform
Eine Normalform ist ein Term n, der keine β- und keine η-Reduktion
zulässt. n ist Normalform von t, falls t →∗ n und n eine Normalform ist.
Wenn ein Term keine Normalform hat, kann man ihn unendlich oft reduzieren.
Beispiele: Die folgenden Terme
sind Normalformen:
a) λ x. (x x)
b) λ x λ y. y y
c) (x λx. λ y. y y )
Beispiele: Die folgenden Terme
haben keine Normalformen:
a) (λ x. x x) ( λ x. x x)
b) λ f. (λ x. f (x x)) (λ x. f (x x)) λ f.
Beispiele: Die folgenden Terme
haben Normalformen:
a) (λ x. x x) ( λ x. x )
b) (λ x. λ y. x y ) λ x. λ y.x
c) λ y. (x λx. λ y. x y ) y
Beispiel: Der folgende Term
t hat eine Normalform, und
eine unendliche Reduktion :
(λ f. λ g. g) ((λ x. x x) ( λ x. x x))
Kann ein Term verschiedene Normalformen haben ?
© H. Peter Gumm, Philipps-Universität Marburg
Diamantlemma von Church und Rosser:
s
s
⇒
t‘
t‘‘
t‘‘
t‘
t
Church & Rosser: Wenn s zu zwei verschiedenen Termen t‘ und t‘‘ reduziert,
dann gibt es einen Term t, zu dem sowohl t‘ als auch t‘‘ reduzieren.
Korollar: Jeder Term hat höchstens eine Normalform.
© H. Peter Gumm, Philipps-Universität Marburg
Konsequenzen aus Church & Rosser
1
Jeder Term hat höchstens eine Normalform.
s
2
3
t
Für zwei Terme gilt genau dann s =αβη t, wenn es
einen Term u gibt mit s →* u und
t →* u.
Man kann keinen falschen Auswertungs-schritt
machen, d.h.: Wenn es einen Term u gibt mit
s →* u und t →* u und man reduziert s →* s‘ und
t →* t‘, dann gibt es auch ein u‘ mit s‘ →* u‘ und
t‘ →* u‘
t
s
s‘
t‘
u
u‘
© H. Peter Gumm, Philipps-Universität Marburg
Auswertungsstrategie
Der Satz von Church & Rosser besagt, daß man durch eine Reduktion
nichts verderben kann. Wenn ein Term sowohl eine Normalform hat,
als auch eine unendliche Auswertungsfolge, dann kann man, egal wie
man angefangen hat, immer noch die Normalform finden. Eine Strategie,
die Normalform zu finden, falls sie existiert, ist:
Reduziere immer den äußersten linken Redex.
Ein Redex ist ein Teilbaum einer der Formen
v
v
v
β-Redex
η-Redex
Dreiecke stehen für beliebige Terme, in denen sich weitere Redexe befinden können.
Beispiel: (λ f. λ g. g) ((λ x. x x) ( λ x. x x))
© H. Peter Gumm, Philipps-Universität Marburg
In einer konkreten Programmiersprache
Die Fakultätsfunktion sei definiert durch:
fac = λ n. if (n= 0) then 1 else n*fac(n-1).
Bei der Auswertung von fac 3 könnten wir immer innen reduzieren:
fac 3 = (λ n. if (n= 0) then 1 else n*fac(n-1)) 3
= (λ n. if (n= 0) then 1
else n*λ n. if (n= 0) then 1
else n*fac(n-1) (n-1)) 3
= (λ n. if (n= 0) then 1
else n*λ n. if (n= 0) then 1
else n* (λ n. if (n= 0) then 1
else n*fac(n-1)) (n-1) (n-1)) 3
...
oder immer außen - hier im if-then-else:
fac 3 = (λ n. if (n= 0) then 1 else n*fac(n-1)) 3
= ( if (3= 0) then 1 else 3*fac(3-1))
= ( if F then 1 else 3*fac(3-1))
= 3*fac(3-1)
= 3 * ((λ n. if (n= 0) then 1 else n*fac(n-1)) (3-1))
=…
= 3 * 2 * 1 * ((λ n. if (n= 0) then 1 else n*fac(n-1)) 0 )
= 3 * 2 * 1 * (if (0= 0) then 1 else 0*fac(0-1))
= 3 * 2 * 1 * if T then 1 else 0*fac(0-1))
=3*2*1*1
= 6.
© H. Peter Gumm, Philipps-Universität Marburg
Kombinatoren
Lambda-Terme mit freien Variablen, sind nicht die Objekte, die uns interessieren.
Wir müssen sie aber betrachten, da sie in der induktiven Definition als Zwischenschritte
entstehen. Das Endergebnis eines Konstruktionsprozesses sollte aber ein Lambda-Term
ohne freie Variablen, ein Kombinator, sein.
Definition : Ein Kombinator ist ein Lambda-Term ohne freie Variablen.
Wir werden eine Reihe von Kombinatoren einführen und ihnen
Namen geben, z.B.
K
für
λ x. λ y. x
Y
für
λ f. (λ x. f (x x)) (λ x. f (x x))
Pair
für
λ x. λ y. λ z. z x y
Konvention: Mit einem einzelnen Großbuchstaben oder einem Wort
bezeichnen wir in der Folge nur Kombinatoren, mit s, t, e beliebige
Lambda-Terme und mit x,y,z,u,v Variablen.
Für eine geschachtelte Abstraktionen benutzen wir die Kurzschreibweise:
λ x1 x2 .... xn. s statt λx1. λx2. ... λxn. s
© H. Peter Gumm, Philipps-Universität Marburg
Programmieren mit dem Lambda-Kalkül
Lambda-Kalkül bisher nur Formalismus, um über Funktionen, ihre
Konstruktion und ihre Anwendung und ihre Gleichheit zu reden.
Was aber sind die Daten, die manipuliert werden können.
Die Booleschen Werte
T
F
:=
:=
λ x y. x
λ x y. y
Der IF-Kombinator
IF
:=
λ x y z. x y z
Lemma : Für beliebige λ-Terme s t gilt:
IF T s t = s
IF F s t = t
© H. Peter Gumm, Philipps-Universität Marburg
Datenstruktur BOOL
Die Booleschen Werte haben wir implementiert als :
T := λ x y. x
F := λ x y. y
Wir definieren die Booleschen Operationen:
OR
:= λ x y. IF x T y
AND := λ x y. IF x y F
NOT := λ x. IF x F T
und erhalten :
OR
T
F
AND
T
F
NOT
T
T
T
T
T
F
T
F
F
T
F
F
F
F
F
T
© H. Peter Gumm, Philipps-Universität Marburg
Paarfunktion
Eine Paarfunktion mit den Umkehrfunktionen liefern
und
Pair := λ x y. λ z. z x y
Fst
:= λ x. x T
Kurzschreibweise:
< s, t > := Pair s t
Snd := λ x. x F
Wir überprüfen leicht
Fst < s, t >
= (Pair s t) T
= (λ z. z s t) T
= Tst
= s
Snd < s, t >
= (Pair s t) F
= (λ z. z s t) F
= Fst
= t
© H. Peter Gumm, Philipps-Universität Marburg
Zahlen
Die natürlichen Zahlen repräsentieren wir durch Kombinatoren
0, 1, 2, .... , die wir induktiv definieren als:
und
0 := λ x. x
n+1 := < F, n >
für n ¸ 0.
Operationen
isZero := Fst
succ := λ x. < F , x >
pred := Snd
Wie definieren wir
add
mult
div
?
?
?
Zeigen Sie:
succ n = n+1
pred n+1 = n
Prüfen Sie, ob gilt :
pred (succ s ) = s
succ( pred s ) = s
Beachte: 3 ist eine natürliche Zahl, 3 ist der Kombinator, der sie repräsentiert,
also 3 = <F,<F,<F,l x.x>>>
© H. Peter Gumm, Philipps-Universität Marburg
Rekursion
Eine Funktion „add“ müsste folgende Gleichungen erfüllen:
add m 0 = m
add m n+1 = succ (add m n)
Wir probieren eine induktive Definition:
add x y = IF (isZero y) x (succ (add x (pred y)))
Wir lösen nach add auf und erhalten eine Fixpunktgleichung :
add x = λy. IF (isZero y) x (succ (add x (pred y)))
add = λx. λy. IF (isZero y) x (succ (add x (pred y)))
add ist also ein Fixpunkt des folgenden Funktionals )*:
Fadd = λ f. λx. λy. IF (isZero y) x (succ (f x (pred y)))
)*
Funktional : ehrfürchtige Bezeichnung für eine Funktion, deren Argument(e) Funktionen sind.-
© H. Peter Gumm, Philipps-Universität Marburg
Ein Fixpunkt für jeden Kombinator
Sei C ein beliebiger Kombinator. Wir betrachten den l-Term
YC := ( λx. C ( x x) ) ( λx. C ( x x) )
Wir behaupten daß YC ein Fixpunkt von C ist, also
C YC = YC
Wir behaupten daß YC ein Fixpunkt von C ist, denn
YC
= ( λx. C ( x x) ) ( λx. C ( x x) )
= C ( λx. C ( x x) ) ( λx. C ( x x) )
= C YC .
© H. Peter Gumm, Philipps-Universität Marburg
Der Fixpunktkombinator
Y
Es gibt einen Kombinator Y, der jedem Kombinator einen Fixpunkt zuordnet:
Y := λ f. ( λx. f ( x x) ) ( λx. f ( x x) )
Satz: Für jeden Kombinator C ist YC ein Fixpunkt von C, also :
C (Y C) = Y C
Beweis : Nachrechnen!
© H. Peter Gumm, Philipps-Universität Marburg
Addition - nächster Versuch
Wir definieren den Kombinator add als Fixpunkt des folgenden Funktionals:
Fadd = λ f. λx. λy. IF (isZero y) x (succ (f x (pred y)))
add := Y Fadd
Wir rechnen:
add 3 1 = Y Fadd 3 1
= Fadd (Y Fadd) 3 1
= λx. λy. IF (isZero y) x (succ ((Y Fadd) x (pred y))) 3 1
= IF (isZero 1) 3 (succ ((Y Fadd) 3 (pred 1)))
= IF F 3 (succ ((Y Fadd) 3 (pred 1)))
= succ ((Y Fadd) 3 (pred 1))
= succ ((Y Fadd) 3 0)
= succ ( Fadd (Y Fadd) 3 0)
= succ (λx. λy. IF (isZero y) x (succ ((Y Fadd) x (pred y))) 3 0)
= succ (IF (isZero 0) 3 (succ ((Y Fadd) 3 (pred 0))))
= succ (IF T 3 (succ ((Y Fadd) 3 (pred 0))))
= succ 3
=4
Zeigen Sie : Für alle natürlichen Zahlen m, n gilt: add
m n = m+n
© H. Peter Gumm, Philipps-Universität Marburg
Zahlentheoretische Funktionen
Multiplikation
Rekursive Definition
mult m 0 = 0
mult m n+1 = add (mult m n) m
Entsprechendes
Funktional :
Fmult = λ f. λ x. λ y. IF (isZero y) 0 (add (f x (pred y)) x )
Endgültige Definition: mult := Y Fmult
Definieren Sie entsprechend : sub, div, mod, isEven.
© H. Peter Gumm, Philipps-Universität Marburg
λ-Definierbarkeit der µ-rekursiven Funktionen
Definition : Eine partielle Funktion f :: Nk ! N ist λ-definierbar,
wenn es einen Kombinator Cf gibt, so dass für alle natürlichen Zahlen
m, n1,...,nk gilt:
f(n1, ... ,nk) = m
⇔
Cf n1 ... nk = m
Satz (Church): Jede µ-rekursive Funktion ist λ-definierbar.
Korollar : Jede Implementierung des λ-Kalküls liefert eine
vollwertige Programmiersprache.
Beispiele : LISP, ML, Haskell, Clean, etc. ...
© H. Peter Gumm, Philipps-Universität Marburg
primitiv rekursiv ⇒ λ-definierbar
Die konstanten Funktionen λ x1 ... xk. m, die Projektionen λ x1 ... xk . xi
und die Nachfolgerfunktion sind offensichtlich λ-definierbar.
,
Seien F, G1, ... , Gn Kombinatoren für die Funktionen f, g1, ..., gn, dann
definiert der Kombinator
λx1, ... , xk. F (G1 x1 ... xk) ... (Gn x1 ... xk)
die Komposition.
Seien G, H Kombinatoren für die Funktionen g:: Nk ! N und h:: Nk+2 ! N,
dann wird die durch primitive Rekursion gegebene Funktion f :: Nk+1 ! N
mit
f(x1, ... ,xk, 0) = g(x1, ... ,xk)
f(x1, ... ,xk, n+1) = h(f(x1, ... ,xk, n),n, x1, ... ,xk)
durch den Fixpunkt YF des folgenden Funktionals definiert:
F = λf.λx1 ... xk y. IF (isZero y) (G x1 ... xk) H ( f x1 ... xk (pred y) ) (pred y) x1 ... xk
© H. Peter Gumm, Philipps-Universität Marburg
µ-rekursiv ⇒ λ-definierbar
Sei die Funktion f :: Nk+1 ! N definierbar durch den Kombinator F,
dann beschreiben wir µ(f) durch die folgende Rekursionsgleichung:
µ(f)(x1,...,xk) = minf(0, x1,...,xk)
wobei minf definiert ist durch
minf(n,x1,...,xk) = IF f(n,x1,...,xk) = 0 then n else minf(n+1,x1,...,xk )
Für minf finden wir einen Kombinator MINf als Fixpunkt des Funktionals
F = λf . λ n. λx1 ... xk. IF (isZero ( F n x1 ... xk)) n ( f (succ n) x1 ... xk ).
Das gesuchte Funktional ist dann:
MUf = MINf 0
Satz: Jede berechenbare Funktion ist λ-definierbar.
© H. Peter Gumm, Philipps-Universität Marburg
Natürliche Zahlen – Version von Church
n
Church definierte die natürlichen Zahlen folgendermaßen
¨
¨
¨
¨
¨
n
Nachfolger und Nullprädikat
¨
¨
n
succ = λn. λf x. n f (f x)
isZero = λn. n (λ x. false) true
Die Addition benötigt keine Rekursion
¨
n
0 = λf λx. x
1 = λf λx. f x
2 = λf λx. f (f x)
…
n = λf λx. f (…(f x)…)
add = λm n. λf x. m f (n f x)
Vorgänger ist komplizierter, aber immer noch ohne Rekursion realisierbar
© H. Peter Gumm, Philipps-Universität Marburg
Inhalt
1.
Prolog
n
DataLog und Prolog
n
Variablen und Terme
n
Backtracking
n
Turing-Vollständigkeit
2.
Der Lambda-Kalkül
n
Lambda-Terme
n
Gebundene Variablen
n
DeBruijn Darstellung
n
Turing-Vollständigkeit
3.
Kombinatorische Logik
n
Kombinatoren
n
Kompilation Lambda-Kalkül
n
Äquivalenz
4.
Objektkalkül
n
Featherweight Java
n
Bool in FJ
n
N in FJ
n
Test
© H. Peter Gumm, Philipps-Universität Marburg
Kombinatorische Logik
n
Funktionen oft durch Reduktionsgleichungen definiert
¨ Add
0x!x
¨ Add s(x) y ! s(Add x y)
n
Berechnung ist Reduktion
n
Kann ein solches Prinzip Turingvollständig sein ?
n
Welche Ausgangsfunktionen werden benötigt ?
© H. Peter Gumm, Philipps-Universität Marburg
Basiskombinatoren S und K
n
Es genügt, zwei Kombinatoren, S und K, zu definieren:
Sxyz
Kxy
n
= xz (yz)
= y
Weitere sind daraus kombinierbar, z.B.
I := SKK
n
Es gilt
¨
I x = S K K x = K x (K x) = x
© H. Peter Gumm, Philipps-Universität Marburg
Kombinatorische Ausdrücke
n
Syntax
e ::= K | S
| x | y | z | ...
| ( e1 e2 )
Ein Kombinator ist ein kombinatorischer Ausdruck ohne Variablen.
Klammerersparung wie üblich :
e1 e2 e3 = (( e1 e2 ) e3 )
S (K K) x
K x (K y)
x
x (y x) S
kombinatorische Ausdrücke
(Linksklammerung)
S (K K)
K S (K K)
S
S (K S) S
Kombinatoren
© H. Peter Gumm, Philipps-Universität Marburg
Reduktionsregeln
Reduktionsregeln definieren Kombinatoren als Abbildungen auf der
.
Menge aller kombinatorischen Ausdrücke
Reduktionsregeln
K e1 e2 → e1
S e1 e2 e3 → e1 e3 (e2 e3)
Gleichheit: Reflexiv, symmetrisch, transitive Kongruenzhülle.
Zusätzlich Extensionalitätsregel:
E1 v = E2 v
⇒
E1 = E2.
Konvention:
Kleinbuchstaben e1, e2, .. für komb. Ausdrücke
Grossbuchstaben K, S, I, E1, E2, .. für Kombinatoren
v, x,y,z für Variablen
© H. Peter Gumm, Philipps-Universität Marburg
Kombinatoren für Daten und Operationen
Zeigen Sie:
Die Booleschen Werte repräsentieren wir durch :
T
F
T e1 e2 → e1
F e1 e2 → e2
:= K
:= KI
Wir definieren die Booleschen Operationen:
OR
OR e1 e2
:= S I (K T)
AND e1 e2 → e1 e2 F
AND := S S (K (K F) )
und erhalten :
→ e1 T e2
NOT e → e F T
NOT := S (S I (K F)) (K T)
OR
T
F
AND
T
F
NOT
T
T
T
T
T
F
T
F
F
T
F
F
F
F
F
T
© H. Peter Gumm, Philipps-Universität Marburg
Paarfunktion
Pair :=
S (S (K S) (S ( S (K S)) (S (S (KS) (S ( S (K S) ) (K (K I) ))) (S (K K) K )))) (K K)
Die Umkehrfunktionen sind einfacher:
Fst
:= S I (K T)
Snd
:= S I (K F)
Prüfen Sie nach (Zähne zusammenbeißen!):
Fst (Pair e1 e2) → e1
Snd (Pair e1 e2) → e1
Wie kommt man auf sowas ?
© H. Peter Gumm, Philipps-Universität Marburg
Zahlen
Die natürlichen Zahlen repräsentieren wir durch Kombinatoren
0, 1, 2, .... , die wir induktiv definieren als:
0 := I
und
n+1 := Pair F n
für n ≥0.
Operationen
isZero := Fst
succ
:= Pair F
pred
:= Snd
© H. Peter Gumm, Philipps-Universität Marburg
Der Fixpunktkombinator
Ein Fixpunktkombinator:
Y := S (S (S (K S) K ) (K (S I I))) (S (S (K S) K ) (K (S I I)))
Leider hilft uns dies nicht, denn wenn wir add finden wollen, müssen
wir zunächst einen Kombinator Cadd für
Fadd = λ f. λx. λy. (isZero y) x (succ (f x (pred y)))
finden. Danach können wir setzen
add := Y Cadd
Wie findet man einen Kombinator für Fadd ?
Allgemeiner :
Wie übersetzt man einen Lambda-Term in Kombinatoren ?
© H. Peter Gumm, Philipps-Universität Marburg
Übersetzung
n
Kombinatorische Ausdrücke in Lambda-Terme:
Kombinatorischer Ausdrücke e repräsentiert
Lambda-Term eL :
SL
KL
xL
(e1 e2)L
n
=
=
=
=
λx.λy.λz. x z (y z)
λx.λy. x
x
e1L e2L
Lambda-Terme in Kombinatorische Ausdrücke ?
Kann man für jeden jedem λ-Term t einen kombinatorischen
Ausdruck tC finden, so dass t = (tC)L = t ?
© H. Peter Gumm, Philipps-Universität Marburg
Kombinatoren für λ-Terme
Kann man für jeden jedem λ-Term t einen kombinatorischen
Ausdruck tC finden, so dass t = (tC)λ ?
Einfache Fälle:
vC
(E1 E2)C
(λ x.E)C
:= v
:= ( (E1)C (E2)C )
:= λ*x. ( EC )
Hilfsfunktion λ*x, wandelt kombinatorischen Ausdruck in einen anderen um,
der die Abstraktion nach x simuliert.
λ*x.
λ*x.
λ*x.
λ*x.
λ*x.
K
S
x
y
(E1 E2)
:=
:=
:=
:=
:=
K
K
I
K
S
K
S
y,
falls x≠y .
(λ*x.E1 ) ( λ*x.E2 )
© H. Peter Gumm, Philipps-Universität Marburg
Korrektheit der Lambda-Abstraktion
E kombinatorischer Ausdruck ⇒ λ*x.E kombinatorischer Ausdruck, der
der Abstraktion nach x entspricht, konkret:
Lemma: Für jeden kombinatorischen Ausdruck E gilt: (λ*x.E)L = λx.EL
Beweis: Induktion über den Aufbau von E.
E ≡ K : (λ*x.K)L = (K K)L = (λx.λy.x) KL = λy.KL
E ≡ S : (λ*x.S)L = (K S)L = λx.SL
E≡x:
(analog )
(λ*x.x)L = IL = λx.x
E ≡ y≠x : (λ*x.y)L = (K y)L = λx. yL
(Warum ?)
E ≡ (E1 E2): (λ*x. E1 E2)L = (S (λ*x. E1) (λ*x. E2))L = SL (λx. E1L) (λx. E2L)
Für einen beliebigen Lambda-Ausdruck U gilt aber
SL (λx. E1L) (λx. E2L) U
= ((λx. E1L) U ) ((λx. E2L) U )
= ( λx. E1L E2L) U
folglich mit Extensionalität:
(λ*x. (E1 E2))L =αβη SL (λx. E1L) (λx. E2L) =αβη λx. (E1 E2)L
© H. Peter Gumm, Philipps-Universität Marburg
Programmieren ohne Variablen
Satz: Für jeden λ-Term t ist tC ein kombinatorischer Term und (tC)L = t.
Beweis: Induktion über den Aufbau von λ-Termen.
X
(xC)L
= (x)L = x.
Nach Voraussetzung: ((E1)C)L = E1 und ((E2)C)L = E2, also
((E1 E2)C)L
= ((E1)C (E2)C )L = E1 E2.
Es gelte bereits (EC)L = E, dann folgt mit dem Lemma:
((λv.E)C)L = (λ*v.EC)L
= λx.(EC)L (nach dem Lemma)
= λx.E (nach Ind.Vorauss.)
Man kann also jeden λ-Term ohne freie Variablen (d.h. jedes [funktionale]
Programm) durch einen variablenfreien Term, also ein variablenfreies
Programm ersetzen. Man muß lediglich ein paar
Hilfsfunktionen - im Prinzip genügen S und K - hinzunehmen.
© H. Peter Gumm, Philipps-Universität Marburg
Beispiel einer Übersetzung
Betrachte den λ-Term T = λx. λy. x
TC
= (λx. λy. x)C
= λ*x.(λy.x)C
= λ*x.(λ*y.x)
= λ*x. (K x)
= S (λ*x. K) (λ*x. x)
= S (K K) I
Mit den Reduktionsregeln und Extensionalität folgt:
TC = S (K K) I = K
Betrachte den λ-Term F = λx. λy. y :
FC
= (λx. λy. y)C
= λ*x.(λy.y)C
= λ*x.(λ*y.y)
= λ*x. I
=KI
Mit den Reduktionsregeln und mit Extensionalität folgt
FC = K I = S K
© H. Peter Gumm, Philipps-Universität Marburg
Optimierungen
Zwei Optimierungen sind einfach. Wenn x nicht in E vorkommt, dann gelten
λ*x. E = K E
und
λ*x. E x = E
Beweis: Induktion über den Aufbau von E.
Verbesserter Kompilationsalgorithmus:
λ*x.
λ*x.
λ*x.
λ*x.
x
E
E x
(E1 E2)
:=
:=
:=
:=
I
K E
, falls x nicht in E vorkommt.
E
, falls x nicht in E vorkommt.
S (λ*x.E1 ) ( λ*x.E2 )
, sonst.
© H. Peter Gumm, Philipps-Universität Marburg
Curry‘s Kombinatoren B und C
Um die häufige Situation, daß bei der Berechnung von λ*x.(E1 E2) in einem der
Teilausdrücke kein x vorkommt, abzufangen, genehmigt sich Curry zwei weitere
Kombinatoren, B und C, mit den Reduktionsregeln:
B f g x → f (g x)
C f g x → f x g
Damit vereinfacht sich die Kompilation weiter, da man die folgenden Vereinfachungsregeln anwenden kann:
SS(K
(KEE1)1)(K
(KEE22))
SS(K
(KE)
E)II
SS(K
(KEE1)1)EE22
SSEE1 (K
(KEE2))
1
2
:=:=
:=:=
:=:=
:=:=
KK(E
(E1 1EE22))
EE
BBEE1 EE2
1 2
CCEE1 EE2
1
2
Übung: Übersetzen Sie mit Hilfe von Curry‘s Algorithmus den Fixpunktkombinator:
YC = ( λf. (λ x. f (x x) ) (λ x. f (x x) ) )C = ???
© H. Peter Gumm, Philipps-Universität Marburg
Compilation eines funktionalen Programms
nKombinatorische
Logik als Grundlage für die Implementierung von
Programmiersprachen wurde 1979 von Turner wiederentdeckt. Er
implementierte auf dieser Basis seine funktionale Sprache „Miranda“.
Gegeben sei das Programm
fact(n) = if n=0 then 1 else fact(n-1)*n
Wir übersetzen es in einen Kombinator:
fact
= Y (λ* f. λ* n. isZero n 1 (mult n (f (pred n)) ))
= Y (λ* f. S (λ* n. isZero n 1) (λ* n. mult n (f (pred n)) ))
= Y (λ* f. S (S (λ* n. isZero n) (K 1)) (λ* n. mult n (f (pred n)) ))
= Y (λ* f. S (S isZero (K 1)) (S mult (S (K f) pred) ))
= Y (λ* f. S (C isZero 1) (S mult (B f pred) ))
=
= Y (S λ* f. S (C isZero 1) ) (λ* f. S mult (B f pred )))
= Y (S (K (S (C isZero 1))) (B (S mult) (λ* f. B f pred )))
= Y (B (S (C isZero 1)) (B (S mult) (S B (K pred )) ))
= Y (B (S (C isZero 1)) (B (S mult) (C B pred )) )
© H. Peter Gumm, Philipps-Universität Marburg
Graphreduktion
nKombinatoren
können durch Bäume repräsentiert werden. Jeder
innere Knoten entspricht einer Applikation.
S (C isZero 1) (S mult (B f pred) )
S
C
1
isZero
S
mult
B
f
pred
© H. Peter Gumm, Philipps-Universität Marburg
Graphreduktion
nEine
Reduktion entspricht einer Graphtransformation:
S e1 e2 e3
→
e1 e3 ( e2 e3 )
e3
reduziert zu
e2
S
C e1 e2 e3
e1
e1
→
e3
e1 e3 e2
e3
reduziert zu
e2
C
e1
e3
e2
e2
e1
e3
© H. Peter Gumm, Philipps-Universität Marburg
Graphreduktion: Beispiel
0
reduziert zu
S
C
1
isZero
S
mult
B
f
pred
0
0
1
C
isZero
S
mult
B
f
pred
© H. Peter Gumm, Philipps-Universität Marburg
Graphreduktion: Beispiel
reduziert zu
. . .
0
1
C
isZero
0
isZero
isZero 0
isZero n+1
Txy
→T
→F
→x
reduziert zu
1
Übung: Werten Sie durch Graphreduktion aus:
S (C isZero 1) (S mult (B f pred) ) 1
T
1
reduziert zu
1
. . .
. . .
© H. Peter Gumm, Philipps-Universität Marburg
Graphreduktion - sharing
Bei der Reduktion werden durch Verwendung neuer Applikationsknoten die
ursprünglichen Bäume erhalten. Dadurch können gemeinsame Unterbäume durch den
gleichen Baum repäsentiert werden.
e3
wird zu
e3
e2
S
e2
e1
S
e1
© H. Peter Gumm, Philipps-Universität Marburg
Graphreduktion mit Rekursion
Rekursion kann durch einen Pfad zurück zur Wurzel repräsentiert werden.
Konkret wird Y (λ* f*. E) durch den Graphen E repräsentiert, in dem man
jedes f durch einen Pfeil zurück zur Wurzel von E ersetzt:
Y (λ* f. S (C isZero 1) (S mult (B f pred) ))
S
C
1
isZero
S
mult
pred
B
f
Übung: Berechnen Sie durch Graphreduktion: fact(3).
© H. Peter Gumm, Philipps-Universität Marburg
Inhalt
1.
Prolog
n
DataLog und Prolog
n
Variablen und Terme
n
Backtracking
n
Turing-Vollständigkeit
2.
Der Lambda-Kalkül
n
Lambda-Terme
n
Gebundene Variablen
n
DeBruijn Darstellung
n
Turing-Vollständigkeit
3.
Kombinatorische Logik
n
Kombinatoren
n
Kompilation Lambda-Kalkül
n
Äquivalenz
4.
Objektkalkül
n
Featherweight Java
n
Bool in FJ
n
N in FJ
n
Test
© H. Peter Gumm, Philipps-Universität Marburg
Objektkalkül
n
n
n
Programmierparadigmen haben schlanken Kern
¨ Rest: Syntactic sugar
Vorteil
¨ Für theoretische Überlegungen ausreichend
¨ Basis für Implementierungen
Beispiele:
¨ Imperatives Programmieren
n
¨
Logisches Programmieren
n
¨
Prolog ohne Cut
Funktionales Programmieren
n
n
¨
While-Sprache
Lambda-Kalkül
Kombinatorische Logik
Objektorientiertes Programmieren ?
n
Featherweight Java - FJ
© H. Peter Gumm, Philipps-Universität Marburg
Featherweight Java
n
Die komplette Syntax
¨ Keine Anweisung – ausser return
¨ Keine Daten
Klasse mit Feldern,
einem Konstruktor
und Methoden
Konstruktor, nur zum
Initialisieren der Felder
Methode mit einziger
Anweisung: return
Expressions
Feldreferenz, Methodenaufruf, Objekterzeugung, Cast
© H. Peter Gumm, Philipps-Universität Marburg
Ist FJ Turing-Vollständig ?
n
Konstruiere folgende
Klassenhierarchie
¨ „abstract“ ist
syntactic sugar
¨
alternativ könnten wir
alle Methoden der
Oberklasse mit
irrelevantem Wert
implementieren
¨
False und True als
Singletons
© H. Peter Gumm, Philipps-Universität Marburg
N in FJ
n
n
Predecessor
speichern
Zahlen sind
¨
¨
¨
¨
n
Zero
Succ(Zero)
Succ(Succ(Zero))
…
„if-then else“ in add
und mult ersetzt
durch Aufteilung in
die Klassen Zero und
Succ
© H. Peter Gumm, Philipps-Universität Marburg
Einige Tests
© H. Peter Gumm, Philipps-Universität Marburg
Herunterladen