3 Exkurs: Der λ-Kalkül - Uni Konstanz, Informatik

Werbung
3 Exkurs: Der λ-Kalkül
Alonso Churchs λ-Kalkül (ca. 1940) ist der formale Kern jeder funktionalen Programmiersprache.
Der λ-Kalkül
I ist eine einfache Sprache, mit nur wenigen syntaktischen Konstrukten und simpler Semantik.
(⇒ Eine Implementation des λ-Kalküls ist leicht zu erhalten und damit eine gute Basis für die Realisierung von
FPLs.)
I ist eine mächtige Sprache. Jede berechenbare Funktion kann im λ-Kalkül dargestellt werden.
(Alle Konzepte, auch die moderner FPLs, lassen sich auf den λ-Kalkül abbilden. Im Prinzip könnten wir einen
Compiler für eine FPL erhalten, indem wir sie auf den λ-Kalkül abbilden und dessen Implementation nutzen.)
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
23
FPL ←→ λ-Kalkül.
Funktionales Programm
Ausführung des Programms
≡
≡
Ausdruck des λ-Kalküls
Auswertung des Ausdrucks durch Reduktion
Primitiver Algorithmus zur Auswertung:
O
1 Wähle nächsten zu reduzierenden Teilausdruck e (Redex, reducible expression).
O
2 Ersetze Redex e durch Reduktionsergebnis e0 .
O
3 Stop, wenn Normalform erreicht. Sonst zurück zu O
1.
2 ab jetzt (sprich: e wird zu e0 reduziert, e reduces to e0 ):
Schreibe für Schritt O
e _ e0
1 und O
3 ) sind Thema des Kapitels 12.
Auswertungsverfahren (insb. die Schritte O
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
24
Beispiel 3.1
Gegeben sei der λ-Ausdruck:
(+ (× 5 6) (× 8 3))
Auswertung durch Reduktion:
Schritt
λ-Ausdruck
Aktion
O
1
Zwei Redexe:
O
2
Reduktion:
O
3
Normalform? Nein, ≥ 1 Redex verbleibt.
(+ 30 (× 8 3))
O
1
Wähle einzigen Redex
(+ 30 (× 8 3))
O
2
Reduktion:
O
3
Normalform? Nein, ≥ 1 Redex verbleibt.
(+ 30 24)
O
1
Wähle einzigen Redex
(+ 30 24)
O
2
Reduktion:
(+ 30 24) _ 54
54
O
3
Normalform? Ja, kein Redex verbleibt. Stop.
54
(× 5 6) und (× 8 3). Wähle ersten (beliebig).
(× 5 6) _ 30
(× 8 3)
(× 8 3) _ 24
(+ 30 24)
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
(+ (× 5 6) (× 8 3))
(+ 30 (× 8 3))
(+ 30 24)
25
3.1
Syntax des λ-Kalküls
Funktionsanwendung.
Juxtaposition von Funktion und Argument, notiert in Prefix-Form:
(f x)
Currying.
Anwendung von f auf mehr als 2 Argumente? Beispiel: Summe von x und y:
((+ x) y)
I Ausdruck (+ x) ist die Funktion, die x zu ihrem Argument addiert,
(Ein funktionswertiger Ausdruck!)
I die dann auf y angewandt wird.
Mittels Currying kann jede Funktion als Funktion eines einzigen Arguments verstanden werden.
Vereinbarung.
Funktionsanwendung ist links-assoziativ. Schreibe daher auch kürzer (+ x y).
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
26
3.1.1
Konstante und vordefinierte Funktionen
Der Kern des λ-Kalküls bietet keine Konstanten (wie 1, "foo", True) oder vordefinierte Funktionen (wie
+, ×, if).
In dieser Vorlesung: um Konstante und entsprechende Reduktionsregeln erweiterter λ-Kalkül.
Beispiel 3.2
Reduktion einiger vordefinierter Funktionen (später: δ-Reduktion _ , siehe Abschnitt 3.3):
δ
(+ x y)
(× x y)
(if True e f )
(if False e f )
(and False e)
(and True e)
_
_
_
_
_
_
x y
x y
e
f
False
e
(Operationen in 2 seien direkt auf der Zielmaschine ausführbar, wenn die Argumente x und y zuvor bis zur Normalform
reduziert wurden)
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
27
3.1.2
λ-Abstraktionen
Mit den sog. λ-Abstraktionen werden im λ-Kalkül neue Funktionen definiert:
λx.e
In dieser λ-Abstraktion ist x der formale Parameter, der im Funktionskörper e zur Definition der
Funktion benutzt werden kann (sprich: x ist in e gebunden, siehe Abschnitt 3.2.1). Der Punkt ‘.’ trennt
x und e.
Beispiel 3.3
Funktion, die ihr Argument inkrementiert:
λx.(+ x 1)
Maximumsfunktion:
λx.(λy.(if (< x y) y x))
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
28
3.1.3
Syntax des λ-Kalküls (Grammatik)
Kontextfreie Grammatik, die syntaktisch korrekte λ-Ausdrücke beschreibt:
e
→
|
|
|
c
v
(e e)
(λv.e)
Konstanten, vordef. Funktionen
Variablen
Applikation (Juxtaposition)
λ-Abstraktion
Treten keine Mehrdeutigkeiten auf, können Klammern (·) weggelassen werden.
Beispiel 3.4
((λx.(+ x 1)) 4)
≡
(λx.(+ x 1)) 4
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
≡
(λx. + x 1) 4
29
3.2
Operationale Semantik des λ-Kalküls
Als zweiten Schritt definieren wir die Bedeutung (Semantik) eines λ-Ausdrucks und legen damit fest, wie
man mit λ-Termen „rechnen“ kann.
3.2.1
Freie und gebundene Variablen
Um den folgenden λ-Ausdruck auszuwerten
(λx. + x y) 4
I wird der hier nicht bekannte „globale“ Wert der Variablen y benötigt, während
I der Wert des Parameters x im Funktionskörper (+ x y) durch das Argument 4 festgelegt ist.
Innerhalb der λ-Abstraktion
I ist der Parameter x (durch das λ) gebunden, während
I die Variable y frei ist.
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
30
Definition 3.1
Eine Variable x ist in einem Ausdruck frei bzw. gebunden:
x ist frei in v
⇐⇒
x ist frei in (e e0)
⇐⇒
x ist frei in (λy.e)
⇐⇒
x=v
(nicht wenn x 6= v oder v = c)
x ist frei in e oder
x ist frei in e0
x 6= y und
x ist frei in e
x ist gebunden in (e e0 )
⇐⇒
x ist gebunden in (λy.e)
⇐⇒
x ist gebunden in e oder
x ist gebunden in e0
(x = y und x ist frei in e) oder
x ist gebunden in e
(in einem Ausdruck, der aus einer einzigen Variablen v bzw. Konstanten c besteht,
ist x nie gebunden)
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
31
Generell hängt der Wert eines Ausdrucks nur von seinen freien Variablen ab.
Beispiel 3.5
In der λ-Abstraktion
λx. + ((λy. × y z) 7) x
sind x und y gebunden, z jedoch frei.
Vorsicht! Bindung/Freiheit muß für jedes Auftreten einer Variable entschieden werden. Ein
Variablenname kann innerhalb eines Ausdrucks gebunden und frei auftreten.
Beispiel 3.6
+ x ((λx. + x 1) 4)
O
1
O
2
1 tritt x frei auf, während x an Position O
2 gebunden vorliegt.
Bei O
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
32
3.2.2
β-Reduktion
Eine λ-Abstraktion beschreibt eine Funktion. Wir definieren hier, wie eine λ-Abstraktion auf ein
Argument angewandt wird.
Definition 3.2
Die Funktionsanwendung
(λx.e) M
wird reduziert zu
I einer Kopie des Funktionsrumpfes e, in der
I die freien Vorkommen von x durch M ersetzt wurden.
Beispiel 3.7
Damit gilt
(λx. + x 1) 4
_
β
+41
_
41
_
5
Die Reduktion _ ist die sog. β-Reduktion des λ-Kalküls.
β
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
33
Beispiel 3.8
Der formale Parameter kann mehrfach oder gar nicht im Funktionsrumpf auftreten:
(λx. + x x) 5
_
(λx.3) 5
_
+55
β
_
10
3
β
In einem Funktionsrumpf kann eine weitere λ-Abstraktion enthalten sein
(Currying in Aktion, vgl. Abschnitt 3.1):
(λx.(λy. × y x)) 4 5
_
β
_
β
_
(λy. × y 4) 5
×54
20
Wir werden im folgenden λx.(λy.e) oft durch λx.λy.e oder gar λx y.e abkürzen.
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
34
Beispiel 3.9
Funktionen können problemlos als Argumente übergeben werden:
(λf.f 3) (λx. + x 1)
_
β
_
β
_
(λx. + x 1) 3
+31
4
Bei β-Reduktion werden nur die freien Vorkommen des formalen Parameters im Funktionsrumpf ersetzt:
(λx.(λx. + (− x 1)) x 3) 9
O
1
_
β
_
β
_
(λx. + (− x 1)) 9 3
+ (− 9 1) 3
11
1 ist durch die innere λ-Abstraktion gebunden und wird daher bei der ersten
Das Vorkommen von x bei O
β-Reduktion nicht ersetzt.
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
35
3.2.3
α-Konversion
Die Bedeutung einer λ-Abstraktion ändert sich nicht, wenn wir ihre formalen Parameter konsistent
umbenennen, d.h. alle gebundenen Vorkommen des Parameters ebenfalls umbenennen:
(λx. × x 2)
]
α
(λy. × y 2)
Manchmal ist diese α-Konversion unerläßlich, um Namenskollisionen und damit fehlerhafte Reduktionen
(sog. „name capture“) zu vermeiden.
Beispiel 3.10
Unter dem Namen TWICE sei folgende Funktion definiert (die ihr erstes Argument zweimal auf ihr
zweites anwendet):
TWICE ≡ (λf.λx.f (f x))
Wir verfolgen jetzt die Reduktion des Ausdrucks (TWICE TWICE ) mittles β-Reduktion.
(TWICE TWICE )
_
≡
_
β
(λf.λx.f (f x)) TWICE
(λx. TWICE (TWICE
| {z x}))
O
2
|
{z
}
O
1
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
36
1 und O
2 . Wir wählen O
2 beliebig:
Es entstehen die Redexe O
_
≡
_
β
(λx.TWICE ((λf.λx.f (f x)) x))
(λx.TWICE (λx.x (x x)))
falsch
Die x sind nun fälschlicherweise durch die innere λ-Abstraktion gebunden (captured). Umbennunng
2:
mittels α-Konversion hilft hier. Nach Reduktion von O
_
≡
]
α
_
β
(λx.TWICE ((λf.λx.f (f x)) x))
(λx.TWICE ((λf.λy.f (f y)) x))
(λx.TWICE (λy.x (x y)))
Beispiel 3.10
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
37
3.3
Zusammenfassung
Probleme wie name capture können die Anwendung der ansonsten simplen β-Reduktionsregel
verkomplizieren. Wir geben hier daher eine endgültige formale Definition der β-Reduktion, die derartige
Probleme berücksichtigt.
Definition 3.3
β-Reduktion:
(λx.e) M
_
β
e[M/x]
e[M/x] (sprich: M für x in e) ist definiert durch
v[M/x]
x[M/x]
(e e0 )[M/x]
(λx.e)[M/x]
(λv.e)[M/x]
=
=
=
=
=
v
M
(e[M/x] e0[M/x])
λx.e
λv.e[M/x]
=
λz.(e[z/v])[M/x]
wenn v 6= x oder v = c
wenn x nicht frei in e ist oder
v nicht frei in M ist
sonst (z neuer Variablenname)
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
38
Damit sind alle Werkzeuge zum Umgang mit dem λ-Kalkül zusammengestellt.
Operationale Semantik des λ-Kalküls:
α-Konversion
λx.e
]
β-Reduktion
(λx.e) M
_
δ-Reduktion
(∗ e)
_
α
β
δ
λy.e[y/x]
e[M/x]
wenn y nicht frei in e ist
e
implementiert ∗ auf der Zielmaschine
Dieses kompakte formale System ist ausreichend, um als Zielsprache für alle funktionalen
Programmiersprachen zu dienen.
I Tatsächlich ist Haskell ein syntaktisch stark angereicherter λ-Kalkül.
I Sprachelemente von Haskell werden wir teilweise auf den λ-Kalkül zurückführen.
© 2003 T. Grust · Funktionale Programmierung: 3. Exkurs: Der λ-Kalkül
39
Herunterladen