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