Funktionales Programmieren Programmierparadigmen Lambda-Kalkuel D. Rösner Institut für Wissens- und Sprachverarbeitung Fakultät für Informatik Otto-von-Guericke Universität Magdeburg c Sommer 2011, 20. Juni 2011, 2011 D.Rösner D. Rösner PGP 2011 . . . 1 Funktionales Programmieren Gliederung 1 Funktionales Programmieren Lambda-Kalkül Einführung Lambda-Ausdrücke Rechenregeln Arithmetik Boolesche Operationen Datenstrukturen Kontrollstrukturen D. Rösner PGP 2011 . . . 2 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Mathematische Funktionen: math.: Funktion ist (eindeutige) Abbildung einer Menge (Urbild, domain) in eine andere Menge (Bildbereich, range) z.B. sqrt: R → R plus: [R × R] → R totale Funktion: alle Elemente des Urbildbereiches besitzen ein Bild andernfalls: partielle Funktion vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 4 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Mathematische Funktionen: Beispiel: Sei f die Funktion, die jeder natürlichen Zahl a die kleinste natürliche Zahl b zuordnet, für die gilt, dass die Ziffern von a in dezimaler Repräsentation in der dezimalen Expansion von π zum ersten Mal nach b Ziffern rechts vom Dezimalpunkt auftauchen z.B. a = 59, π = 3,14159, f (59) = 4 Frage: Ist f total oder partiell? vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 5 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Funktionen als Mengen: Funktionen sind Teilmengen des kartesischen Produkts aus Urbild- und Bildbereich z.B. sqrt ⊂ [R × R] plus ⊂ [R × R × R] in Mengennotation: sqrt ≡ {(x, y ) ∈ R × R|y = x 2 } plus ≡ {(x, y , z) ∈ R × R × R|z = x + y } beachte: dies sind intensionale Darstellungen, aber keine Berechnungsvorschriften vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 6 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Funktionen sind math. Objekte: Wenn f Funktion von A nach B, dann ist f Teilmenge von A × B, d.h. f ist Element der Potenzmenge von A × B, d.h. der Menge aller Teilmengen von A × B, kurz: 2A×B wegen der geforderten Eindeutigkeit sind nicht alle Elemente von 2A×B Funktionen von A nach B D. Rösner PGP 2011 . . . 7 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Funktionen sind math. Objekte: Funktionsraum A → B: diejenigen Elemente von 2A×B , bei denen in jedem Paar die erste Komponente eindeutig (A → B) ⊂ 2A×B höhere Funktionen in Mengennotation, z.B. compose ≡ {(f , g, h)|∀x ∈ R : h(x) = f (g(x))} compose ∈ [(R → R) × (R → R)] → (R → R) D. Rösner PGP 2011 . . . 8 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Lambda-Kalkül Lambda-Ausdruck: rekursive Definition Lambda-Ausdruck ist entweder 1 2 3 4 Name Lambda-Abstraktion aus λ, Name, Punkt und Lambda-Ausdruck Funktionsanwendung aus zwei nebeneinander stehenden Lambda-Ausdrücken geklammerter Lambda-Ausdruck vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 10 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Lambda-Kalkül meist zusätzliche Vorrangregeln: Funktionsanwendung linksassoziativ, d.h. f A B interpretiert als (f A) B (und nicht f (A B)) Anwendung hat höhere Präzedenz als Abstraktion, d.h. λ x.AB interpretiert als λ x.(A B) (und nicht (λ x.A)B) vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 11 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Lambda-Kalkül kontextfreie Grammatik (CFG) für Lambda-Ausdrücke mit minimaler Klammernzahl expr → name|number| λ name . expr | func arg func → name|(λ name . expr) | func arg arg → name|number| (λ name . expr) | (func arg) Bemerkung: es wird unterschieden zwischen Lambda-Ausdrücken, die als Funktionen (s. func) , und solchen, die als Argumente verwendet werden (s. arg). vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 12 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Lambda-Kalkül mit λ werden formale Parameter eingeführt der mit λ eingeführte Name wird im nachfolgenden Ausdruck als gebunden bezeichnet und der Ausdruck ist der Gültigkeitsbereich (Skopus) für diesen Namen eine nicht gebundene Variable heißt frei freie Variable müssen in einem umgebenden Skopus gebunden sein Beispiel: in λ x.λ y. times x y ist x gebunden, in λ y. times x y ist x frei D. Rösner PGP 2011 . . . 13 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Lambda-Kalkül Ein Name < name > ist frei in einem λ-Ausdruck, wenn einer der drei Fälle zutrifft: < name > ist frei in < name >. < name > ist frei in λ < name1 > . < exp >, wenn der Identifikator < name >6=< name1 > und < name > ist frei in < exp > < name > ist frei in E1 E2 wenn < name > ist frei in E1 oder < name > ist frei in E2 s.a. [?] D. Rösner PGP 2011 . . . 14 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Lambda-Kalkül Ein Name < name > ist gebunden in einem λ-Ausdruck, wenn einer der zwei Fälle zutrifft: < name > ist gebunden in λ < name1 > . < exp >, wenn der Identifikator < name >=< name1 > oder < name > ist gebunden in < exp > < name > ist gebunden in E1 E2 wenn < name > ist gebunden in E1 oder < name > ist gebunden in E2 ein Identifikator kann in einem Ausdruck sowohl frei als auch gebunden vorkommen Beispiel: (λx.xy )(λy .y ) s.a. [?] D. Rösner PGP 2011 . . . 15 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Lambda-Kalkül zur vereinfachten Referenz können Ausdrücken Namen (im Sinne von Synonymen oder Kurzschreibweisen) gegeben werden z.B. square ≡ λx.times x x identity ≡ λx.x const7 ≡ λx.7 hypot ≡ λx.λy. sqrt (plus (square x) (square y)) lies: ≡ ‘ist Abkürzung für’ D. Rösner PGP 2011 . . . 16 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül Zum Rechnen mit dem Lambda-Kalkül genügen im wesentlichen drei Rechenregeln: β-Reduktion α-Konversion η-Reduktion D. Rösner PGP 2011 . . . 18 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül β-Reduktion: Für jede λ-Abstraktion λx.E und jeden Ausdruck M: (λx.E)M →β E[M \ x] Dabei bezeichnet E[M \ x] den Ausdruck E mit allen freien Vorkommen von x ersetzt durch M. Anwendungsbedingung: β-Reduktion ist nicht erlaubt, wenn irgendwelche in M freien Variablen in E[M \ x] gebunden würden. D. Rösner PGP 2011 . . . 19 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül Anwendungsbedingung der β-Reduktion: verhindert sog. Variablenergreifen (engl. variable capture) Beispiel: würde der Ausdruck (λx.(λy .xy ))y ohne Beachtung der Anwendungsbedingung β-reduziert, so ergäbe sich (λy .yy ) das korrekte Resultat ergibt sich, wenn zunächst eine Umbenennung vorgenommen wird (λx.(λy .xy ))y → (λx.(λt.xt))y → (λt.yt) s.a. [?] D. Rösner PGP 2011 . . . 20 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül α-Konversion: Für jede λ-Abstraktion λx.E und jede Variable y, die keine freien Vorkommen in E hat: λx.E →α λy .E[y \ x] η-Reduktion: Für jede λ-Abstraktion λx.E, wobei E von der Form F x und x hat keine freien Vorkommen in F: λx.Fx →η F (überflüssige λ-Abstraktionen eliminieren) vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 21 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Bemerkungen zu den Rechenregeln: β-Reduktion: ähnelt Parameterübergabe durch call-by-name; unbeabsichtigtes ‘Ergreifen’ (capture) einer Variable wird durch die Anwendungsbedingung verhindert α-Konversion: Umbenennungen, damit β-Reduktion möglich η-Reduktion: von geringerer Bedeutung wenn square wie oben definiert, dann mit η-Reduktion erlaubt: λx.square x →η square vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 22 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül zusätzlich für Arithmetik (falls nicht direkt innerhalb des Kalküls behandelt) : δ-Reduktion ein Ausdruck der Form op x y mit x, y numerische Literale und op aus kleiner Menge von Standardfunktionen kann durch arithmetischen Wert ersetzt werden Beispiele: plus 2 3 →δ 5 minus 5 2 →δ 3 times 2 3 →δ 6 vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 23 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül β-Reduktion und α-Konversion (und ggf. η-Reduktion) werden wiederholt angewendet, bis keine weitere Reduktion möglich ist und der λ-Ausdruck sich in seiner einfachsten Form befindet Church-Rosser [1936]: einfachste Formen sind eindeutig jede Folge von Reduktionen, die in einem nicht weiter reduzierbaren Ausdruck endet, produziert das gleiche Resultat beachte: Termination ist nicht garantiert Beispiel: (λx.xx)(λx.xx) →β . . . vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 24 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül Reduktion in Normalordnung: wenn mehr als eine β-Reduktion möglich, wird hierbei diejenige gewählt, deren λ am weitesten links im gesamten Ausdruck steht Beispiel: (λf.λg.λh.fg(hh))(λx.λy.x)h(λx.xx) →β . . . vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 25 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül Arithmetik mit natürlichen Zahlen lässt sich wie folgt im λ-Kalkül darstellen: benötigt wird eine Darstellung für Null sowie eine Darstellung für Nachfolger-Funktion (engl. successor) n-fache Anwendung der Nachfolger-Funktion auf Null repräsentiert dann die jeweilige Zahl n die so dargestellten Zahlen werden auch als Church-Numerale bezeichnet vgl. u.a. [?] D. Rösner PGP 2011 . . . 26 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül eine Darstellung für natürliche Zahlen im λ-Kalkül 0 ≡ λs.(λz.z) auch geschrieben als: λsz.z die Definitionen weiterer Zahlen: 1 ≡ λsz.s(z) 2 ≡ λsz.s(s(z)) 3 ≡ λsz.s(s(s(z))) ... vgl. u.a. [?] D. Rösner PGP 2011 . . . 27 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül die Nachfolger-Funktion lässt sich durch folgenden Kombinator darstellen: S ≡ λwyx.y(wyx) Bemerkung: als Kombinatoren werden λ-Ausdrücke ohne freie Variable bezeichnet Frage: Was ergibt die Anwendung von S auf 0, 1, . . . ? ................................ ................................ ................................ vgl. u.a. [?] D. Rösner PGP 2011 . . . 28 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül die Addition zweier Zahlen m und n wird zurückgeführt auf die m-fach wiederholte Anwendung der Nachfolger-Funktion auf die Zahl n Beispiel: 2 + 3 wird berechnet durch die Reduktion von (λsz.s(s(z)))(λwyx.y(wyx))(λuv.u(u(u(v)))) ................................ ................................ ................................ vgl. u.a. [?] D. Rösner PGP 2011 . . . 29 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül die Multiplikation zweier Zahlen m und n wird realisiert durch die Anwendung der Funktion λxyz.x(yz) auf die Zahlen m und n Beispiel: 2 ∗ 2 wird berechnet durch die Reduktion von (λxyz.x(yz))2 2 ................................ ................................ ................................ vgl. u.a. [?] D. Rösner PGP 2011 . . . 30 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül Beispiel: 2 ∗ 2 wird berechnet durch die Reduktion (hier in Normalordnung) von (λxyz.x(yz))2 2 →β λz.2 (2 z) →Def .2 λz.(λst.s(s t))(2 z) →β λz.λt.(2 z)(2 z t) →Def .2 λz.λt.((λuv.u(u v))z)(2 z t) →β λz.λt.(λv.z(z v))(2 z t) ... D. Rösner PGP 2011 . . . 31 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül Beispiel: cont. ... →β λz.λt.z(z (2 z t))) →Def .2 λz.λt.z(z ((λuv.u(u v)) z t)) →β λz.λt.z(z ((λv.z (z v)) t)) →β λz.λt.z(z (z (z t))) →Def .4 4 D. Rösner PGP 2011 . . . 32 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül auch die booleschen Werte T und F werden durch Funktionen repräsentiert T ≡ λxy.x F ≡ λxy.y als Funktionen werden die beiden Wahrheitswerte auch als select_first bzw. select_second bezeichnet vgl. u.a. [?], [Sco00] D. Rösner PGP 2011 . . . 33 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül die logischen Verknüpfungen lassen sich dann wie folgt definieren: ∧ ≡ λxy.xy(λuv.v) ≡ λxy.xyF ∨ ≡ λxy.x(λuv.u)y ≡ λxy.xTy Negation eines Arguments ergibt sich mit ¬ ≡ λx.x(λuv.v)(λab.a) ≡ λx.xFT vgl. u.a. [?] D. Rösner PGP 2011 . . . 34 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül Negation angewendet auf T ergibt ¬T ≡ λx.x(λuv.v)(λab.a) (λcd.c) reduzierbar zu: ................................ ................................ ................................ vgl. u.a. [?] D. Rösner PGP 2011 . . . 35 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül Paare (a, b) lassen sich als Funktion wie folgt darstellen: λz.zab die Selektion des ersten bzw. zweiten Elements des Paares erfolgt dann durch Anwendung dieser Funktion auf T bzw. F (λz.zab)T = . . . (λz.zab)F = . . . vgl. u.a. [?] D. Rösner PGP 2011 . . . 36 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül mit Paaren lassen sich weitere nützliche Funktionen definieren Beispiel: Vorgängerfunktion (engl. predecessor) Grundidee: kreiere Paare der Form (n, n − 1) und selektiere das zweite Element Umsetzung: die folgende Funktion ordnet einem Paar (n, n − 1) das Paar (n + 1, n) zu: Φ ≡ (λpz.z(S(pT))(pT)) vgl. u.a. [?] D. Rösner PGP 2011 . . . 37 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül die Vorgängerfunktion P gewinnen wir dann mit folgendem Vorgehen: wende Φ n-mal auf das Paar λz.z00 an und selektiere dann das zweite Element des entstandenen Paares im λ-Kalkül: P ≡ λn.nΦ(λz.z00)F vgl. u.a. [?] D. Rösner PGP 2011 . . . 38 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül eine bedingte Verzweigung lässt sich als Funktion wie folgt darstellen: if ≡ λc.λt.λe.cte vgl. [Sco00], Ch. 11.2.4 D. Rösner PGP 2011 . . . 39 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Rechnen mit dem Lambda-Kalkül das erstaunlichste Ergebnis über den λ-Kalkül ist die Darstellbarkeit rekursiver Funktionen eine zentrale Rolle dabei spielt der Operator Y, definiert durch: Y ≡ λh.(λx.h(xx))(λx.h(xx)) vgl. [Sco00], Ch. 11.2.4 eine besonders detaillierte Herleitung von Y liefert [?] D. Rösner PGP 2011 . . . 40 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Literatur: I Chris Barker. Lambda Tutorial, interactive tutorial. http://homepages.nyu.edu/ cb125/Lambda/. Henk Barendregt and Erik Barendsen. Introduction to Lambda Calculus, 2000. revised; ftp://ftp.cs.ru.nl/pub/CompMath.Found/lambda.pdf. Kostas Chatzikokolakis. LCI - A lambda calculus interpreter, an open source interpreter. http://lci.sourceforge.net/. D. Rösner PGP 2011 . . . 41 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Literatur: II Richard P. Gabriel. The Why of Y, 2001. http://www.dreamsongs.com/NewFiles/WhyOfY.pdf. Achim Jung. A short introduction to the Lambda Calculus, 2004. http://www.cs.nyu.edu/rgrimm/teaching/sp10-pl/lambdacalculus.pdf. Raul Rojas. A Tutorial Introduction to the Lambda Calculus, 1997/1998. tutorial notes; http://www.inf.fu-berlin.de/lehre/WS03/alpi/lambda.pdf. D. Rösner PGP 2011 . . . 42 Funktionales Programmieren Lambda-Kalkül Lambda-Ausdrücke Rechenregeln Literatur: III Michael Lee Scott. Programming Language Pragmatics. Academic Press, San Diego, CA, USA, 2000. ISBN 1-55860-578-9. D. Rösner PGP 2011 . . . 43