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