Funktionale Programmierung und Typtheorie

Werbung
Funktionale
Programmierung
und Typtheorie
Francesco Kriegel
TU Dresden
Fakultät Mathematik
Institut Algebra
WS 2008 / 2009
16. April 2010
Inhaltsverzeichnis
Kapitel 1 Der λ-Kalkül
1.1 Ungetypter Lambda-Kalkül . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.1 Definition und Syntax. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.2 Beispiele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.3 Reduktion und Normalform . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.4 Fixpunkte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.5 Curryfizierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1.6 primitiv-rekursive und µ-rekursive Funktionen . . . . . . . .
1.1.7 Kombinatorische Logik . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Getypter Lambda-Kalkül. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.1 Monomorph getypter Lambda-Kalkül λ→ . . . . . . . . . . . . .
1.2.2 Polymorph getypter Lambda-Kalkül λ2 . . . . . . . . . . . . . . .
1.2.3 Polymorph getypter Lambda-Kalkül λ3 . . . . . . . . . . . . . . .
1.2.4 Curry-Howard-Isomorphismus . . . . . . . . . . . . . . . . . . . . . .
3
3
3
6
7
10
11
12
14
16
16
20
21
22
Kapitel 2 Haskell
2.1 Grundprinzipien. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.1 referentielle Transparenz . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.2 Auswertungsstrategien . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.3 funktionale Programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.4 Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.5 algebraische Datenstrukturen (abstrakte und rekursive
Datentypen) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.6 Pattern Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.7 Polymorphie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.8 Typklassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.9 Typinferenz. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.10 Komprehensionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.11 Funktionen höherer Ordnung und partielle Applikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.12 strikte und nicht-strikte Funktionen. . . . . . . . . . . . . . . . . . .
2.1.13 Parser. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
23
23
23
23
24
24
24
24
25
25
27
28
28
28
1
2.1.14 Konstruktorklassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2 Verifikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.1 Wohlfundierte Induktion . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3 Transformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.1 Fold-Unfold-Methode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.2 Bird-Meertens-Formalismus . . . . . . . . . . . . . . . . . . . . . . . . .
2.4 Monaden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
28
29
29
31
31
32
34
1 Der λ-Kalkül
1.1 Ungetypter Lambda-Kalkül
1.1.1 Definition und Syntax
Definition 1.1 (λ-Term)
Für eine mindestens abzählbar unendliche Menge V von Variablen ist
die Menge Λ der λ-Terme über V induktiv definiert durch:
(i) x ∈ V =⇒ x ∈ Λ
(ii) A ∈ Λ =⇒ (λx.A) ∈ Λ
(Abstraktion)
(iii) A, B ∈ Λ =⇒ ( AB) ∈ Λ
(Applikation)
Bemerkung 1.2 Für die Darstellung von λ-Termen benutzen wir folgende Notationen:
(a) Die äußersten Klammern können weggelassen werden.
(b) Wir schreiben A ≡ B, falls die λ-Terme A und B syntaktisch äquivalent
sind.
(c) Der Rumpf einer Abstraktion geht so weit wie möglich nach rechts,
d.h.
λx.( AB) ≡ λx.AB
für alle x ∈ V und A, B ∈ Λ.
(d) Abstraktion ist rechtsassoziativ und die λ-Bindungen werden zusammengefasst, d.h.
λx1 (λx2 (. . . (λxn .A) . . . )) ≡ λx1 .λx2 . . . . λxn .A ≡ λx1 x2 . . . xn .A
für alle x1 , x2 , . . . , xn ∈ V und A ∈ Λ.
3
1 Der λ-Kalkül
(e) Applikation ist linksassoziativ, d.h.
( AB)C ≡ ABC
für alle A, B, C ∈ Λ.
Definition 1.3 (freie und gebundene Variable)
(a) Für einen λ-Term A ist FV( A) die Menge der freien Variablen, und
FV( A) ist induktiv definiert durch
(i) FV( x ) = { x }
(ii) FV(λx.A) = FV( A) \ { x }
(iii) FV( AB) = FV( A) ∪ FV( B)
für alle x ∈ V und A, B ∈ Λ.
(b) Eine Variable x heißt frei in A, wenn x ∈ FV( A).
(c) Ein λ-Term A mit FV( A) = ∅ heißt geschlossener λ-Term oder Kombinator.
(d) Λ0 := { A ∈ Λ | FV( A) = ∅} ist die Menge aller Kombinatoren.
(e) Entsprechend ist BV( A) die Menge der gebundenen Variablen, und
BV( A) ist induktiv definiert durch
(i) BV( x ) = ∅
(ii) BV(λx.A) = BV( A) ∪ { x }
(iii) BV( AB) = BV( A) ∪ BV( B)
Definition 1.4 (Teilterme)
Für einen λ-Term A ist Sub( A) die Menge der Teilterme, und diese ist
induktiv definiert durch:
(i) Sub( x ) = { x }
(ii) Sub(λx.B) = {λx.B} ∪ Sub( B)
(iii) Sub( BC ) = { BC } ∪
S
n
S
D1 ...Dn = BC i =1
Sub( Di )
Ein λ-Term B heißt Teilterm von A, falls B ∈ Sub( A), und wir schreiben
dafür auch B ⊂ A.
4
1.1 Ungetypter Lambda-Kalkül
Definition 1.5 (Substitution)
Für eine Variable x und λ-Terme A, B ist A[ x := B] die Substitution von
x durch B in A, und ist induktiv definiert durch:
(i) x [ x := B] ≡ B
(ii) y[ x := B] ≡ y
(iii) (λx.C )[ x := B] ≡ λx.C
(iv) (λy.C )[ x := B] ≡ λy.(C [ x := B]) für x ∈
/ Sub(C ) oder y ∈
/ FV( B)
(v) (λy.C )[ x := B] ≡ λz.(C [y := z][ x := B]) sonst
(vi) (CD )[ x := B] ≡ (C [ x := B])( D [ x := B])
Dabei sind die Variablen x, y, z paarweise verschieden und z ∈
/ Sub( B) ∪
Sub(C ).
Satz 1.6 (Substitutionslemma) Es gilt
A[ x := B][y := C ] ≡ A[y := C ][ x := B[y := C ]]
für Variablen x, y und λ-Terme A, B, C mit x 6= y und x ∈
/ FV(C ).
Definition 1.7 (λ-Kalkül)
Die Theorie λ hat als Formeln Gleichungen
A=B
für λ-Terme A, B ∈ Λ. Wir nennen λ auch λ-Kalkül. Es gelten folgende
Axiome für alle x, y ∈ V und A, B, C ∈ Λ:
(i) A = A
(ii) A = B =⇒ B = A
(iii) A = B ∧ B = C =⇒ A = C
(reflexiv)
(symmetrisch)
(transitiv)
(iv) A = B =⇒ AC = BC ∧ CA = CB
(v) A = B =⇒ λx.A = λx.B
(ξ )
(vi) λx.A = λy.A[ x := y] für y ∈
/ FV( A)
(α)
(vii) (λx.A) B = A[ x := B] für BV( A) ∩ FV( B) = ∅
( β)
5
1 Der λ-Kalkül
(viii) λx.Ax = A für x ∈
/ FV( A)
(η )
Die Beweisbarkeit einer Gleichung im λ-Kalkül symbolisieren wir mit
λ ` A = B oder einfach A = B, und dann heißen A und B konvertierbar.
Es gilt stets A ≡ B =⇒ A = B, aber nicht umgekehrt.
1.1.2 Beispiele
B OOLEsche Terme
true ≡ λab.a
false ≡ λab.b
or ≡ λab.atrueb
and ≡ λab.abfalse
not ≡ λa.afalse true
ifthenelse = ite ≡ λabc.abc
Satz 1.8 Es gelten ifthenelse trueAB ≡ A und ifthenelse falseAB ≡ B.
Paare
pair ≡ λpq f . f pq
fst ≡ λp.ptrue
snd ≡ λp.pfalse
Listen
cons ≡ pair
hd ≡ fst
tl ≡ snd
nil ≡ λ f .true
null ≡ λl.l (λht.false)
6
1.1 Ungetypter Lambda-Kalkül
Zahlen
Für F, X ∈ Λ und n ∈ N definieren wir die Potenz F n X induktiv durch:
(i) F0 X = X
(ii) F n+1 X = F ( F n X )
Definition 1.9 (C HURCH-Zahlen)
Die C HURCH-Zahlen Cn sind definiert als
Cn ≡ λ f x. f n x
mit den Operationen:
(i) Nulltest iszero ≡ λn.n(λx.false)true
(ii) Nachfolgerbildung succ ≡ λn f x. f (n f x )
(iii) Addition add ≡ λmn f x.m f (n f x )
(iv) Multiplikation mult ≡ λmn f .m(n f )
(v) Exponentiation exp ≡ λmn.mn
Satz 1.10 Es gelten:
(i) iszeroC0 ≡ true und iszero(succCn ) ≡ false
(ii) succCn ≡ Cn+1
(iii) addCm Cn ≡ Cm+n und addCm Cn ≡ succm Cn
(iv) multCm Cn ≡ Cm·n und multCm Cn ≡ (addCn )m C0
(v) expCm Cn ≡ Cnm und expCm Cn ≡ (multCn )m C1
pred = λn.snd(nh(pairC0 C0 ))
h = λp.pair(succ(fstp))(fstp)
1.1.3 Reduktion und Normalform
Definition 1.11 (Λ-Hülle, ρ-Reduktion, ρ-Äquivalenz)
Sei ρ eine binäre Relation auf Λ.
7
1 Der λ-Kalkül
(a) Die Λ-Hülle →ρ von ρ ist eine binäre Relation auf Λ und wird induktiv definiert durch:
(i) ( A, B) ∈ ρ =⇒ A →ρ B
(ii) A →ρ B =⇒ AC →ρ BC ∧ CA →ρ CB
(iii) A →ρ B =⇒ λx.A →ρ λx.B
Für A →ρ B sagen wir auch, A ist in einem Schritt ρ-reduzibel zu B,
und A heißt ρ-Redex und B heißt ρ-Kontraktum.
(b) Die ρ-Reduktion ⇒ρ ist die reflexive, transitive Hülle von →ρ , d.h.
es gelten
(i) A →ρ B =⇒ A ⇒ρ B
(ii) A ⇒ρ A
(iii) A ⇒ρ B ∧ B ⇒ρ C =⇒ A ⇒ρ C
Für A ⇒ρ B sagen wir auch, A ist ρ-reduzibel zu B.
(c) Die ρ-Konvertibilität ist die von →ρ erzeugte Äquivalenzrelation,
d.h. die symmetrische, transitive Hülle von ⇒ρ und es gelten:
(i) A ⇒ρ B =⇒ A =ρ B
(ii) A =ρ B =⇒ B =ρ A
(iii) A =ρ B ∧ B =ρ C =⇒ A =ρ C
Für A =ρ B sagen wir auch, A und B sind ρ-konvertibel.
Wir verwenden obige Definitionen für diese drei Relationen:
α := {(λx.A, λy.A[ x := y]) | x, y ∈ V ∧ A ∈ Λ ∧ y ∈
/ FV( A)}
β := {((λx.A) B, A[ x := B]) | x ∈ V ∧ A, B ∈ Λ ∧ BV( A) ∩ FV( B) = ∅}
η := {(λx.Ax, A) | x ∈ V ∧ A ∈ Λ ∧ x ∈
/ FV( A)}
Definition 1.12 (β-Normalform)
(i) Ein λ-Term A ist in β-Normalform, wenn er keine β-Redexe als Teilterme enthält.
(ii) Ein λ-Term A hat eine β-Normalform, wenn es einen λ-Term B in
β-Normalform mit A = β B gibt.
(iii) Ein λ-Term A heißt schwach β-normalisierend, falls eine endliche
8
1.1 Ungetypter Lambda-Kalkül
Reduktionsfolge A → β A1 → β A2 → β . . . → β An existiert, sodass
An eine β-Normalform ist.
(iv) Ein λ-Term A heißt stark β-normalisierend, falls jede Reduktionsfolge A → β A1 → β A2 → β . . . endlich ist.
Satz 1.13
(i) Nicht jeder λ-Term hat eine β-Normalform, d.h. nicht alle λ-Terme sind schwach normalisierend.
(ii) Es ist nicht entscheidbar, ob ein λ-Term eine β-Normalform besitzt.
Beweis:
(i) Der λ-Term (λx.xx )(λx.xx ) hat keine β-Normalform.
(ii) Beweis über Halteproblem.
Lemma 1.14 Falls A ∈ Λ in β-Normalform ist, dann gilt
A ⇒ β B =⇒ A = B.
Beweis: Für eine β-Normalform A gibt es kein B mit A → β B. Also kann A ⇒ β
B nur wegen der Reflexivität von ⇒ β gelten, d.h. A = B.
Theorem 1.15 (Erstes C HURCH -R OSSER-Theorem) Seien A, B, C drei λTerme mit A ⇒ β B und A ⇒ β C. Dann gibt es einen λ-Term D mit B ⇒ β
D und C ⇒ β D.
Folgerung 1.16
(i) Falls A = β B, so existiert ein λ-Term C mit A ⇒ β C
und B ⇒ β C.
(ii) Falls A eine β-Normalform B hat, dann gilt A ⇒ β B.
(iii) Ein λ-Term hat höchstens eine β-Normalform.
Definition 1.17 (LO- und LI-Reduktion)
(i) Eine LO-Reduktion ist eine Reduktion, bei der der am weitesten
links stehende (leftmost ) Redex, der in keinem anderen enthalten ist (outermost ), reduziert wird. Andere Bezeichnungen sind
Normal-Order-Reduction und Call-by-Name-Mechanismus.
(ii) Eine LI-Reduktion ist eine Reduktion, bei der der am weitesten
links stehende (leftmost ) Redex, der keinen anderen enthält (in-
9
1 Der λ-Kalkül
nermost ), reduziert wird. Andere Bezeichnungen sind ApplicativeOrder-Reduction und Call-by-Value-Mechanismus.
Theorem 1.18 (Zweites C HURCH -R OSSER-Theorem, Normalisierungstheorem) Wenn ein λ-Term A eine β-Normalform B hat, dann existiert
eine Folge von LO-Reduktionen von A zu B.
1.1.4 Fixpunkte
Theorem 1.19
(i) Jeder λ-Term F besitzt einen Fixpunkt X ∈ Λ, d.h. es
gilt FX = X.
(ii) Es existiert ein Fixpunktkombinator Y ≡ λ f .(λx. f ( xx ))(λx. f ( xx )),
sodass F (YF ) = YF für alle λ-Terme F gilt.
Satz 1.20 Die folgenden Terme sind ebenfalls Fixpunktkombinatoren:
(i) Yn = λ f .Xnn = λ f . Xn . . . Xn mit Xn = λx1 . . . xn−1 . f ( x1 x1 . . . xn−1 )
| {z }
n-mal
für n ≥ 2. Speziell ist Y = Y2 .
(ii) Y ∗ ≡ λ f .(λgx. f ( gg) x )(λgx. f ( gg) x )
(iii) Yn∗ = λ f .Bnn = λ f . Bn . . . Bn mit Bn = λx1 . . . xn . f ( x1 x1 . . . xn−1 ) xn
| {z }
n-mal
für n ≥ 2. Speziell ist Y ∗ = Y2∗ .
(iv) Θ = (λxy.y( xxy))(λxy.y( xxy))
(v) $ ≡ £26 ≡ ££££££££££££££££££££££££££
mit £ ≡ λabcde f ghijklmnopqstuvwxyzr.r (thisisa f ixedpointcombinator )
(vi) Θn = Ann = An . . . An mit An = λx1 . . . xn .xn ( x1 x1 . . . xn ) für n ≥ 2.
| {z }
n-mal
Speziell ist Θ = Θ2 und $ = Θ26 .
Mit dem Fixpunkttheorem sind rekursive Definitionen möglich. Möchte
man eine Funktion f durch den λ-Term A rekursiv definieren, d.h. f = A
und f ∈ FV( A), so erhält man die syntaktisch korrekte Definition vermöge
f = Y (λ f .A).
10
1.1 Ungetypter Lambda-Kalkül
Beispiel 1.21
(i) Eine intuitive Definition für die Fakultätsfunktion wäre beispielsweise
fac = λn.ite(iszeron)C1 (multn(fac(predn))).
Die Anwendung des Fixpunktkombinators ergibt
fac = Y (λfac.λn.ite(iszeron)C1 (multn(fac(predn))))
(ii) Das Konkatenieren zweier Listen kann rekursiv definiert werden
durch
append = λxy.ite(nullx )y(cons(hdx )(append(tlx )y))
und syntaktisch korrekt muss die Definition also
append = Y (λappend.λxy.ite(nullx )y(cons(hdx )(append(tlx )y)))
lauten.
(iii) Das Erzeugen einer unendlichen Liste, die nur aus Nullen besteht,
kann durch
zeroes = consC0 zeroes
rekursiv definiert werden. Mit dem Fixpunktkombinator haben wir
zeroes = Y (λzeroes.consC0 zeroes).
1.1.5 Curryfizierung
Aus der Mathematik ist bekannt, dass für Mengen A, B und C stets die
Isomorphie
( A × B) → C ∼
= A → (B → C)
gilt, das bedeutet für eine Funktion f : ( A × B) → C, dass es eine Funktion f 0 : A → ( B → C ) mit f 0 ( a) = (b 7→ f ( a, b)) gibt, sodass f ( a, b) =
f 0 ( a)(b) gilt. Das funktioniert auch im λ-Kalkül mit den Termen
curry2 = λ f xy. f ( x, y)
und
uncurry2 = λ f p. f (fstp)(sndp)
11
1 Der λ-Kalkül
und allgemein für n Variablen
curryn = λ f x1 . . . xn . f ( x1 , . . . , xn )
und
uncurryn = λ f p. f (fstp) . . . (lstp).
Damit lässt sich die λ-Abstraktion generalisieren zu
λ( x1 , . . . , xn ).A = uncurryn (λx1 . . . xn .A)
und entsprechend ergibt sich die β-Reduktion dann zu
(λ( x1 , . . . , xn ).A)( B1 , . . . , Bn ) = A[ x1 := B1 , . . . , xn := Bn ],
wobei keine der Variablen x1 , . . . , xn frei in B1 , . . . , Bn vorkommen dürfen.
1.1.6 primitiv-rekursive und µ-rekursive Funktionen
Definition 1.22 (numerisch, λ-definierbar)
Eine Funktion f : Nn → N heißt numerische Funktion. Eine numerische
Funktion f heißt λ-definierbar, falls es einen λ-Term F gibt, sodass für
alle x1 , . . . , xn ∈ N
C f ( x1 ,...,xn ) = FCx1 . . . Cxn
gilt.
Definition 1.23 (Grundfunktion, Komposition, primitive Rekursion, primitiv-rek
(i) Die Grundfunktionen sind die drei numerischen Funktionen
• Projektion ( x1 , . . . , xn ) 7→ xi
• Nullfunktion ( x1 , . . . , xn ) 7→ 0
• Nachfolgerfunktion x 7→ x + 1.
(ii) Die Komposition f = g[h1 , . . . , hn ] : Nm → N von numerischen
Funktionen g : Nn → N und h1 , . . . , hn : Nm → N ist definiert
durch
f ( x1 , . . . , xm ) := g(h1 ( x1 , . . . , xm ), . . . , hn ( x1 , . . . , xm )).
(iii) Die primitive Rekursion f : Nn+1 → N zweier numerischer Funk-
12
1.1 Ungetypter Lambda-Kalkül
tionen g : Nn+2 → N und h : Nn → N ist definiert durch
f (0, y1 , . . . yn ) := h(y1 , . . . , yn )
f ( x + 1, y1 , . . . yn ) := g( f ( x, y1 , . . . yn ), x, y1 , . . . yn ).
(iv) Eine numerische Funktion heißt primitiv-rekursive Funktion, wenn
sie durch Kompositionen und primitive Rekursionen aus den Grundfunktionen entsteht.
Satz 1.24 Jede primitiv-rekursive Funktion ist λ-definierbar. Insbesondere gelten:
(i) Die Grundfunktionen sind λ-definierbar vermöge
• Projektion λx1 . . . xn .xi
• Nullfunktion λx1 . . . xn .C0
• Nachfolgerfunktion λn f x. f (n f x ).
(ii) Falls g und h1 , . . . , hn λ-definierbar sind, dann ist deren Komposition f λ-definierbar als
F = λx1 . . . xm .G ( H1 x1 . . . xm ) . . . ( Hn x1 . . . xm ).
(iii) Falls g und h λ-definierbar sind, dann ist deren primitive Rekursion
f λ-definierbar als
F = Y (λFxy1 . . . yn .ite(iszerox )( Hy1 . . . yn )( G ( F (predx )y1 . . . yn )(predx )y1 . . . yn ))
Definition 1.25 (µ-Rekursion, µ-rekursive Funktion)
(i) Die µ-Rekursion f = µg : Nn → N einer numerischen Funktion
g : Nn+1 → N ist definiert durch
f ( x1 , . . . , xn ) := min{y | g( x1 , . . . , xn , y) = 0}.
(ii) Eine numerische Funktion heißt µ-rekursive Funktion, falls sie durch
Kompositionen, primitive Rekursionen und µ-Rekursionen aus
den Grundfunktionen entsteht.
13
1 Der λ-Kalkül
Satz 1.26 Jede µ-rekursive Funktion ist λ-definierbar. Insbesondere gilt:
Falls g λ-definierbar ist, dann ist deren µ-Rekursion f λ-definierbar als
F = HC0
H = Y (λH.λyx1 . . . xn .ite(iszero( Gx1 . . . xn y))y( H (succy) x1 . . . xn )).
Theorem 1.27 Die Turing-berechenbaren Funktionen entsprechen genau den µ-rekursiven Funktionen. Daher ist jede Turing-berechenbare
Funktion auch λ-definierbar. Umgekehrt gilt sogar, dass jede λdefinierbare Funktion auch Turing-berechenbar ist.
1.1.7 Kombinatorische Logik
Definition 1.28 (CL-Term)
Für eine mindestens abzählbar unendliche Menge V von Variablen ist
die Menge CL der CL-Terme über V induktiv definiert durch:
(i) x ∈ V =⇒ x ∈ CL
(ii) K, S ∈ CL
(iii) A, B ∈ CL =⇒ ( AB) ∈ CL
(Applikation)
Definition 1.29 (schwache Reduktion)
Auf den CL-Termen ist eine schwache Reduktion →w definiert durch
(i) KAB →w A
(ii) SABC →w AC ( BC )
Analog zum λ-Kalkül wird die mehrfache schwache Reduktion durch
⇒w gekennzeichnet. Jeder der in den drei Reduktionsregeln links stehenden CL-Terme heißt schwacher Redex und jeder der rechts stehenden
CL-Terme heißt schwaches Redukt.
Definition 1.30 (schwache Normalform)
Ein CL-Term ist in schwacher Normalform, wenn er keine schwachen
Redexe enthält.
Bemerkung 1.31
(i) Die Definitionen und Sätze aus dem Abschnitt
1.1.3 gelten entsprechend auch für CL-Terme und die schwache Re-
14
1.1 Ungetypter Lambda-Kalkül
duktion. Insbesondere gelten auch das Church-Rosser-Theorem und
das Normalisierungstheorem.
(ii) Die Reduktion →w wird schwach genannt, weil es CL-Terme in schwacher Normalform gibt, deren transformierter λ-Term nicht in β-Normalform
ist. Beispiel: KI = (λxy.x )(λx.x )
Satz 1.32
(i) Transformation von CL-Termen in λ-Terme
(·)λ : CL → Λ
( x )λ = x
( AB)λ = ( A)λ ( B)λ
(K)λ = λxy.x
(S)λ = λxyz.xz(yz)
(ii) Transformation von λ-Termen in CL-Terme
(·)CL : Λ → CL
( x )CL = x
( AB)CL = ( A)CL ( B)CL
(λx.A)CL = λ∗ x.( A)CL
λ∗ : V × CL → CL
λ∗ x.x = I
λ∗ x.A = KA für A 6= x
∗
λ x.AB = S(λ∗ x.A)(λ∗ x.B)
Definition 1.33 (CL-Kombinatoren)
Die CL-Kombinatoren sind definiert als folgende λ-Terme:
• Identität: I = SKK = λx.x
• Kanzellator: K = λxy.x
• Distributor: S = λxyz.xz(yz)
• Kompositor: B = λxyz.x (yz)
• Permutator: C = λxyz.xzy
15
1 Der λ-Kalkül
Es gelten
S(KA)(KB) = K( AB)
S(KA)I = A
S(KA) B = BAB
SA(KB) = CAB
1.2 Getypter Lambda-Kalkül
1.2.1 Monomorph getypter Lambda-Kalkül λ→
implizite Typung (Curry)
T := VT | (T→T)
Λ := V | (λV.Λ) | (ΛΛ)
(λx.A) B → β A[ x := B]
Definition 1.34 (Typumgebung)
Eine rechts-eindeutige Relation
Γ ⊆ V×T
heißt Typumgebung. Für ein Element ( x, τ ) einer Typumgebung schreiben wir auch
x:τ.
Weiter setzen wir
dom(Γ) := ΓT = { x ∈ V | ∃τ ∈ T : x:τ ∈ Γ}
cod(Γ) := VΓ = {τ ∈ T | ∃ x ∈ V : x:τ ∈ Γ}
sowie
und
für X ⊆ V.
16
Γ, x:τ := Γ ∪ { x:τ }
Γ| X := Γ ∩ ( X × T) = { x:τ ∈ Γ | x ∈ X }
1.2 Getypter Lambda-Kalkül
Definition 1.35 (Typaussage, Wohltypung)
Eine Typaussage ist von der Form
Γ ` A:τ
für eine Typumgebung Γ, einen λ-Term A und einen Typ τ. Für ∅ ` A:τ
schreiben wir einfach ` A:τ. Ein λ-Term A heißt wohlgetypt, falls es eine
Typumgebung Γ und einen Typ τ gibt, sodass Γ ` A:τ gilt. In diesem
Fall heißt τ eine Wohltypung für A.
x:τ ∈ Γ
(Axiom)
Γ ` x:τ
Γ, x:τ ` A:σ
(→-Introduktion)
Γ ` (λx.A):(τ→σ )
Γ ` A:(τ→σ), Γ ` B:τ
(→-Elimination)
Γ ` ( AB):σ
Satz 1.36 (Basislemma)
(i) Γ ` A:τ, Γ ⊆ Γ0 =⇒ Γ0 ` A:τ
(ii) Γ ` A:τ =⇒ FV( A) ⊆ dom(Γ)
(iii) Γ ` A:τ =⇒ Γ|FV( A) ` A:τ
Satz 1.37 (Generierungslemma)
(i) Γ ` x:τ =⇒ x:τ ∈ Γ
(ii) Γ ` (λx.A):τ =⇒ ∃σ, ρ ∈ T : Γ, x:σ ` A:ρ, τ = (σ→ρ)
(iii) Γ ` ( AB):τ =⇒ ∃σ ∈ T : Γ ` A:(σ→τ ), Γ ` B:σ
Lemma 1.38 Für einen wohlgetypten λ-Term sind auch alle Teilterme
wohlgetypt.
Satz 1.39 (Substitutionslemma)
(i) Γ, x:τ ` A:σ, y ∈
/ FV( A) =⇒ Γ, y:τ ` ( A[ x := y]):σ
(ii) Γ ` (λx.A):τ, y ∈
/ FV( A) =⇒ Γ ` (λy.( A[ x := y])):τ
(iii) Γ ` A:τ =⇒ (Γ[σ := ρ]) ` A:(τ [σ := ρ])
(iv) Γ, x:τ ` A:σ, Γ ` B:τ =⇒ Γ ` ( A[ x := B]):σ
17
1 Der λ-Kalkül
Theorem 1.40 (Typerhaltungstheorem) Es gilt
Γ ` A:τ, A ⇒ β B =⇒ Γ ` B:τ.
Theorem 1.41 (Turing)
normalisierend.
Alle wohlgetypten λ-Terme sind stark β-
Definition 1.42 (A:τ?, A:?, ?:τ)
(i) Typprüfungsproblem A:τ?: Sei eine Typumgebung Γ, ein λ-Term A
und ein Typ τ gegeben. Gilt Γ ` A:τ?
(ii) Typisierbarkeitsproblem A :?: Sei eine Typumgebung Γ und ein λTerm A gegeben. Gibt es einen Typ τ, sodass Γ ` A:τ gilt?
(iii) Typbewohntheitsproblem ?:τ: Sei eine Typumgebung Γ und ein Typ
τ gegeben. Gibt es einen λ-Term A, sodass Γ ` A:τ gilt?
Satz 1.43 Die drei Probleme A:τ?, A:? und ?:τ sind für den monomorph
getypten λ-Kalkül λ → entscheidbar.
Der Fixpunktkombinator
Y = λ f .(λx. f ( xx ))(λx. f ( xx ))
aus dem ungetypten λ-Kalkül ist im monomorph getypten λ-Kalkül λ →
nicht wohlgetypt. Das liegt daran, dass die Selbstapplikation ( xx ) nicht
wohlgetypt ist, denn wäre Γ ` ( xx ):τ, so folgt mit dem Generationslemma die Existenz eines Typs σ mit Γ ` x: (σ → τ ) und Γ ` x:σ. Wegen der
Rechtseindeutigkeit einer Typumgebung folgt also σ = (σ→τ ), aber dies
ist kein gültiger Typ, weil er nicht endlich ist.
Damit wäre nun keine Rekursion im getypten λ-Kalkül möglich, und es
wären viele Funktionen nicht definierbar. Als Ausweg führen wir für jeden Typ einen eigenen Fixpunktpunktkombinator als Konstante mit einer
sogenannten δ-Konversionsregel ein.
Definition 1.44 (Fixpunktkombinator)
Für jeden Typ τ definieren wir einen Fixpunktkombinator
Yτ :((τ→τ )→τ )
18
1.2 Getypter Lambda-Kalkül
zusammen mit der δ-Konversionsregel
Yτ F → δ F (Yτ F )
für beliebige λ-Terme F:(τ→τ ).
explizite Typung (Church)
T := VT | (T→T)
Λ := V | (λV:T.Λ) | (ΛΛ)
(λx:τ.A) B → β A[ x := B]
x:τ ∈ Γ
(Axiom)
Γ ` x:τ
Γ, x:τ ` A:σ
(→-Introduktion)
Γ ` (λx:τ.A):(τ→σ )
Γ ` A:(τ→σ), Γ ` B:τ
Γ ` ( AB):σ
(→-Elimination)
Satz 1.45 (Eindeutigkeitslemma)
(i) Γ ` A:τ, Γ ` A:σ =⇒ τ = σ
(ii) Γ ` A:τ, Γ ` B:σ, A = β B =⇒ τ = σ
Definition 1.46 ()
Die Abbildung | · | : Λexp → Λimp ordnet jedem explizit getypten λTerm einen implizit getypten λ-Term zu, indem die Typinformationen
der gebundenen Variablen entfernt werden.
| x | := x
|(λx:τ.A)| := (λx.| A|)
|( AB)| := (| A|| B|)
Satz 1.47
(i) Für alle A ∈ Λexp gilt Γ ` A:τ =⇒ Γ ` | A|:τ
(ii) Für alle A ∈ Λimp gilt Γ ` A:τ =⇒ ∃ B ∈ Λexp : A = | B|, Γ ` B:τ
19
1 Der λ-Kalkül
1.2.2 Polymorph getypter Lambda-Kalkül λ2
implizite Typung (Curry)
T := VT | (T→T) | (∀VT .T)
Λ := V | (λV.Λ) | (ΛΛ)
(λx.A) B → β A[ x := B]
x:τ ∈ Γ
(Axiom)
Γ ` x:τ
Γ, x:τ ` A:σ
(→-Introduktion)
Γ ` (λx.A):(τ→σ)
Γ ` A:(τ→σ ), Γ ` B:τ
Γ ` ( AB):σ
Γ ` A:τ, σ ∈
/ FV(Γ)
Γ ` A:(∀σ.τ )
Γ ` A:(∀σ.τ )
Γ ` A:(τ [σ := ρ])
(→-Elimination)
(∀-Introduktion)
(∀-Elimination)
Satz 1.48 Die drei Probleme A:τ?, A:? und ?:τ sind für den polymorph
implizit getypten λ-Kalkül zweiter Ordnung λ2 nicht entscheidbar.
Satz 1.49 In polymorph getypten λ-Kalkül zweiter Ordnung λ2 sind alle Funktionen λ-definierbar, die in Peano-Arithmetik zweiter Ordnung
terminieren. Das sind unter anderem alle primitiv-rekursiven Funktionen.
explizite Typung (Church)
T := VT | (T→T) | (∀VT .T)
Λ := V | (λV:T.Λ) | (ΛΛ) | (ΛVT .Λ) | (ΛT)
(λx:τ.A) B → β A[ x := B]
(Λτ.A)σ → β A[τ := σ]
x:τ ∈ Γ
Γ ` x:τ
20
(Axiom)
1.2 Getypter Lambda-Kalkül
Γ, x:τ ` A:σ
Γ ` (λx:τ.A):(τ→σ )
Γ ` A:(τ→σ), Γ ` B:τ
Γ ` ( AB):σ
(→-Introduktion)
(→-Elimination)
Γ ` A:τ, σ ∈
/ FV(Γ)
(Λσ.A):(∀σ.τ )
(∀-Introduktion)
Γ ` A:(∀σ.τ )
Γ ` ( Aρ):(τ [σ := ρ])
(∀-Elimination)
Satz 1.50 Die beiden Probleme A:τ? und A:? sind für den polymorph explizit getypten λ-Kalkül zweiter Ordnung λ2 entscheidbar. Das Problem
?:τ ist in λ2 nicht entscheidbar.
1.2.3 Polymorph getypter Lambda-Kalkül λ3
K := ∗ | (K⇒K)
T := VT | (T→T) | (∀VT::K.T) | (λVT::K.T) | (TT)
Λ := V | (λV:T.Λ) | (ΛΛ) | (ΛVT::K.Λ) | (ΛT)
(λx:τ.A) B → β A[ x := B]
(Λτ::k.A)σ → β A[τ := σ]
(λτ::k.σ)ρ → β σ[τ := ρ]
τ::k ∈ Γ
(Axiom 1)
Γ ` τ::k
Γ ` τ::∗, Γ ` σ::∗
(→-∗-Regel)
Γ ` (τ→σ )::∗
Γ, σ::k ` τ::∗, σ ∈
/ FV(Γ)
Γ ` (∀σ::k.τ )::∗
(∀-∗-Regel)
Γ ` A:τ, Γ ` σ::∗, τ = β σ
(β-∗-Konvertibilität)
Γ ` A:σ
Γ, τ::k ` σ::l
(⇒-Introduktion)
Γ ` (λτ::k.σ )::(k⇒l )
Γ ` τ::(k⇒l ), Γ ` σ::k
Γ ` (τσ)::l
(⇒-Elimination)
21
1 Der λ-Kalkül
Γ ` τ::∗, x:τ ∈ Γ
(Axiom 2)
Γ ` x:τ
Γ ` τ::∗, Γ, x:τ ` A:σ
(→-Introduktion)
Γ ` (λx:τ.A):(τ→σ )
Γ ` A:(τ→σ ), Γ ` B:τ
Γ ` ( AB):σ
(→-Elimination)
Γ, σ::k ` A:τ, σ ∈
/ FV(Γ)
Γ ` (Λσ::k.A):(∀σ::k.τ )
(∀-Introduktion)
Γ ` A:(∀σ::k.τ ), Γ ` ρ::k
Γ ` ( Aρ):(τ [σ := ρ])
(∀-Elimination)
1.2.4 Curry-Howard-Isomorphismus
Theorem 1.51 (Curry-Howard-Isomorphismus)
(i) Γ ` A:τ =⇒ cod(Γ) ` τ
(ii) Γ0 ` τ =⇒ ∃ A ∈ Λ : Γ ` A:τ mit Γ = { xτ :τ | τ ∈ Γ0 }
22
2 Haskell
2.1 Grundprinzipien
2.1.1 referentielle Transparenz
Haskell ist referentiell transparent, d.h. ein Variable hat an allen Stellen ihres Geltungsbereich denselben Wert. Dies ermöglicht einen mathematischen Umgang mit Programmen, d.h. Programmeigenschaften können
recht einfach bewiesen und Programme transformiert werden.
2.1.2 Auswertungsstrategien
Call-by-Value: LI-Reduktion, strike Auswertung, eager evaluation, application order reduction
Call-by-Name: LO-Reduktion, nicht-strikte Auswertung, normal order reduction
Call-by-Need: lazy evaluation; eine nicht-strikte Auswertung, bei der Ausdrücke, die zum Ergebnis beitragen und mehrmals auftreten, nur einmal
ausgewertet werden
2.1.3 funktionale Programme
Ein funktionales Programm ist eine Folge von Funktionsdefinitionen.
f1 x11 . . . x1m1 = A1
..
.
fn xn1 . . . xnmn = An
Die Auswertung einer Funktionsdefinition ist die Belegung ihrer Variablen durch Werte.
f B1 . . . Bn = A[x1:=B1,. . . ,xn:=Bn]
Funktionen können auch rekursiv definiert sein.
23
2 Haskell
2.1.4 Typen
Haskell ist eine getypte Sprache und verwendet das H INDLEY-M ILNERTypsystem. Es gibt Basistypen und Typkonstruktoren, wie → und ×, die
zusammengesetzte Typen erzeugen.
Haskell ist stark getypt, d.h. zur Laufzeit können keine Fehler durch Anwendung von Funktionen auf Argumente des falschen Typs entstehen.
Haskell ist statisch getypt, d.h. zur Übersetzungszeit sind die Typen aller
Ausdrücke bekannt, sie werden automatisch inferiert.
2.1.5 algebraische Datenstrukturen (abstrakte und
rekursive Datentypen)
Eine algebraische Datenstruktur wird durch einen Typkonstruktor sowie endlich vielen Datenkonstruktoren definiert. Datenstrukturen können auch rekursiv definiert sein. Damit sie endlich sind, müssen jedoch auch nullstellige Datenkonstruktoren vorhanden sein. Zum Beispiel haben Listen
den Typkonstruktor [], den nullstelligen Datenkonstruktor [] und zweistelligen Datenkonstruktor :.
2.1.6 Pattern Matching
Funktionsdefinitionen von Funktionen auf algebraischen Datenstrukturen können intuitiv durch Pattern Matching geschrieben werden, indem
für bestimmte Muster von Argumenten jeweils eine eigene Definition erfolgt, sodass alle möglichen Fälle abgedeckt sind. Geeignete Muster sind
stets die verschiedenen Datenkonstruktoren eines Datentyps. Beispielsweise kann die Funktion zur Ermittlung der Länge einer Liste rekursiv
definiert werden:
length [] = 0
length (h:t) = 1 + (length t)
2.1.7 Polymorphie
parametrische Polymorphie: Eine Funktion ist parametrisch polymorph, wenn
sie auf verschiedenen Typen gleichartig wirkt. Zum Beispiel die Funktion
length.
Ad-Hoc-Polymorphie: Eine Funktion ist Ad-Hoc-polymorph, wenn sie überladen ist, d.h. wenn sie auf verschiedenen Typen auch verschiedenartig
wirkt. Dies tritt in Typklassen auf.
24
2.1 Grundprinzipien
2.1.8 Typklassen
Eine Typklasse ist eine Menge von Typen, die durch die Namen und Typen
der auf sie anwendbaren Operationen charakterisiert ist.
class <context> <class> <type> where <definitions>
Ein Element einer Typklasse heißt Instanz dieser Typklasse.
instance <context> <class> <type> where <definitions>
Die Namen der Operationen sind überladen, da sie in allen Instanzen
der Typklasse gleich bezeichnet sind, aber unterschiedliche Definitionen
haben können. Die Operationen sind also Ad-Hoc-polymorph. Die Typklassen sind hierarchisch geordnet.
2.1.9 Typinferenz
Sei V eine abzählbar unendliche Menge von Variablen und Θ = n∈N Θn
eine Menge von Typkonstruktoren, wobei Θn die Menge der n-stelligen
Typkonstruktoren ist. Die Menge Θ0 entspricht der Menge der Basistypen. Die Menge T = Typ(V, Θ) der polymorphen Typen über V und Θ
ist definiert durch
S
T ::= V | ( T→T ) | (ΘT . . . T )
Eine Funktionsdefinition hat die Form
f x1 . . . xn = A
und dabei sind die xi Variablen oder Datenkonstruktorapplikationen.
Anhand dieser Gleichung kann der Typ von f inferiert werden.
(i) Analyse der äußeren Struktur: Es gilt
f :: a1 -> . . . -> an -> a
Falls xi eine Datenkonstruktorapplikation ist, so kann der Typ ai
durch eine entsprechende Typkonstruktorapplikation konkretisiert
werden. Analog für A und a. Beispielsweise folgt aus xi = [] oder
xi = (h:t), dass ai = [b] ein Listentyp ist.
(ii) Analyse der inneren Struktur: Für jede Applikation BC im Rumpf A
wird eine Typgleichung der Form
typ(B) = typ(C) -> typ(BC)
25
2 Haskell
aufgestellt. Bereits bekannte Typen werden sofort eingefügt, sonst
werden stets neue Variablen verwendet.
(iii) Unifikation: Die Menge der Typgleichungen
{τi = σi | i ∈ I }
wird unifiziert, d.h. es wird mit dem Unifikationsalgorithmus von
R OBINSON eine Substitution
φ : V → Typ(V, Θ)
berechnet, deren homomorphe Fortsetzung
φ̂ : Typ(V, Θ) → Typ(V, Θ)
die Menge der Typgleichungen löst, d.h. es gilt
φ̂(τi ) = φ̂(σi )
für alle i ∈ I. φ̂ heißt auch Unifikator. Die homomorphe Fortsetzung
φ̂ ist definiert durch
φ̂(τ ) := φ(τ )
für alle Variablen τ ∈ V,
φ̂(τ→σ ) := (φ̂(τ )→φ̂(σ ))
für Funktionstypen und
φ̂(θτ1 . . . τn ) := (θ φ̂(τ1 ) . . . φ̂(τn ))
für Strukturtypen. Nach dem Satz von R OBINSON existiert für eine Menge von Typgleichungen stets ein (bis auf Umbenennung von
Typvariablen) eindeutiger allgemeinster Unifikator, den man durch
die homomorphe Fortsetzung der Lösung des Unifikationsalgorithmus von R OBINSON erhält. Ein Unifikator φ heißt allgemeinster Unifikator, falls es für jeden weiteren Unifikator ψ eine Substitution
ρ : V → Typ(V, Θ)
mit
ψ = ρ̂ ◦ φ
26
2.1 Grundprinzipien
gibt.
uni f y(τ, σ ) =i f (τ ∈ V ∧ τ * σ ) then (τ 7→ σ )
elsei f (σ ∈ V ∧ σ * τ ) then (σ 7→ τ )
elsei f ((τ ∈ Θ0 ∨ σ ∈ Θ0 ) ∧ τ = σ ) then id
elsei f (τ = τ1→τ2 ∧ σ = σ1→σ2 )
then uni f ylist([τ1 , τ2 ], [σ1 , σ2 ], id)
elsei f (τ = θτ1 . . . τn ∧ σ = θσ1 . . . σn )
then uni f ylist([τ1 , . . . , τn ], [σ1 , . . . , σn ], id)
else f ail
uni f ylist([], [], φ) =φ
uni f ylist(τ : t, σ : s, φ) =let (ψ = uni f y(φ(τ ), φ(σ )))
in i f (ψ = f ail ) then f ail else uni f ylist(t, s, ψ ◦ φ)
2.1.10 Komprehensionen
Eine Mengenkomprehension ist beispielsweise
M = {n2 | n ∈ N, n mod 2 = 0}
und eine entsprechende Listenkomprehension ist
l = [nˆ2|n <- [0..],n ‘mod‘ 2 == 0].
Allgemein sind Listenkomprehensionen von der Form
[A|q1,. . . ,qn],
wobei die qi
(i) Generatoren pattern <- list mit pattern :: a und list :: [a],
(ii) Selektoren predicate :: Bool, oder
(iii) lokale Bindungen let expression, die in nachfolgenden Generatoren und Selektoren gelten,
sein können. Es gelten
[A|p <- l] = map (\p -> A) l
[A|b] = if b then [A] else []
[A|let e] = let e in [A]
[A|q1,q2] = [[A|q2]|q1]
27
2 Haskell
2.1.11 Funktionen höherer Ordnung und partielle
Applikation
Eine Funktion, die eine andere Funktion als Argument oder Ergebnis hat,
heißt Funktion höherer Ordnung. Eine Unterversorgung einer Funktion mit
Argumenten heißt auch partielle Applikation.
2.1.12 strikte und nicht-strikte Funktionen
Eine nicht-terminierende Berechnung wird mit ⊥ symbolisiert. Eine Funktion f heißt strikt im i-ten Argument, wenn ihre Berechnung genau dann
nicht terminiert, wenn die Berechnung des i-ten Elements nicht terminiert, d.h. falls f ( x1 , . . . , xi−1 , ⊥, xi+1 , . . . , xn ) = ⊥ für alle x j gilt. Andernfalls heißt f nicht-strikt im i-ten Argument. f heißt strikt, wenn f strikt in
allen Argumenten ist, andernfalls nicht-strikt.
2.1.13 Parser
Parser implementieren Erkennungsmechanismen für Sprachen. Sie stellen nach Eingabe eines Textes fest, ob dieser zur Sprache gehört oder
nicht. Im Fall der Zugehörigkeit gibt der Parser eine Untergliederung des
Textes in Struktureinheiten an. Parser können beispielsweise den Datentyp
type Parser tok a = [tok] -> [(a,[tok])]
verwenden.
2.1.14 Konstruktorklassen
Konstruktorausdrücke sind entweder Konstruktorvariablen, Typkonstruktoren oder Konstruktorapplikationen. Jeder Konstruktorausdruck hat einen
Kind. Eine Konstruktorklasse ist eine Menge von Typkonstruktoren gleichen Kinds. Zum Beispiel die Klasse der Monaden oder der Funktoren.
class <context> <class> <type> where <definitions>
instance <context> <class> <type> where <definitions>
28
2.2 Verifikation
2.2 Verifikation
2.2.1 Wohlfundierte Induktion
Definition 2.1 (wohlfundierte Menge)
Eine geordnete Menge ( M, ≤) heißt wohlfundiert, falls jede nichtleere
Teilmenge von M (mindestens) ein minimales Element besitzt.
Theorem 2.2 (wohlfundierte Induktion) Sei ( M, ≤) eine wohlfundierte
Menge und P ein Prädikat über M. Dann gilt
h∀ x ∈ M : {[∀y < x : P(y)] =⇒ P( x )}i =⇒ [∀ x ∈ M : P( x )].
Beweis: Für alle x ∈ M gelte [∀y < x : P(y)] =⇒ P( x ). Sei
X := { x ∈ M | ¬ P( x )},
angenommen es gäbe ein x ∈ M mit ¬ P( x ), d.h. X 6= ∅. Dann existiert wegen der
Wohlfundiertheit ein minimales Element x0 von X mit ¬ P( x0 ). Weil x0 ein minimales Element ist, folgt für alle y < x0 stets y ∈
/ X, also P(y). Nach Voraussetzung
ergibt sich damit aber P( x0 ). Widerspruch!
Möchte man also die Gültigkeit eines Prädikats P für alle Elemente einer
wohlfundierten Menge ( M, ≤) zeigen, so geht man schrittweise vor:
(i) Induktionsanfang: Man zeigt, dass P für alle minimalen Elemente von
M gilt.
(ii) Induktionsschritt: Unter der Voraussetzung, dass P für alle Elemente
y < x gilt, zeigt man dass P auch für x gilt.
Beispiel 2.3 Die vollständige Induktion ist eine wohlfundierte Induktion über der wohlfundierten Menge (N, ≤) der natürlichen Zahlen mit
der üblichen Ordnung.
Definition 2.4 (algebraischer Datentyp)
Ein algebraischer Datentyp ist definiert durch
Dτ1 . . . τn = C1 σ11 . . . σ1k1 | . . . | Cm σm1 . . . σmkm
für m > 0, k i ∈ N und σij ∈ T für i ∈ {0, . . . , m} und j ∈ {0, . . . , k i }.
Dabei ist
T = T 0 | ( Dτ1 . . . τn )
T0 = V | W | (T0 , . . . , T0 ) | (T0 → T0 )
29
2 Haskell
und W ist die Menge aller konstanten Typen sowie aller algebraischen
Datentypen. Die Ci heißen Konstruktoren und haben folgende Eigenschaften:
(i) Die Konstruktoren sind disjunkt, d.h. aus Ci xi1 . . . xiki = Cj y j1 . . . y jk j
folgt i = j.
(ii) Die Konstruktoren sind injektiv, d.h. aus Ci xi1 . . . xiki = Ci yi1 . . . yiki
folgt xij = yij .
(iii) Die Konstruktoren sind surjektiv, d.h. für alle x ∈ Dτ1 . . . τn gibt
es ein i mit x = Ci yi1 . . . yiki .
Beispiel 2.5
(i) Die strukturelle Induktion über einen algebraischen
Datentyp D ist eine wohlfundierte Induktion über der wohlfundierten Menge (D , ≤). Die minimalen Elemente von (D , ≤) sind die Elemente der Konstruktoren, die D nicht beinhalten. Die Elemente der
Konstruktoren, die D beinhalten, sind echt größer als die Elemente
von D , aus denen sie konstruiert werden.
(ii) Die Listeninduktion ist eine strukturelle Induktion über den algebraischen Datentyp
L = Listτ = Empty | Consτ (Listτ ).
Das einzige minimale Element ist hier Empty und es gilt L < ConsxL
für alle x ∈ τ und L ∈ L.
(iii) Die Bauminduktion ist eine strukturelle Induktion über den algebraischen Datentyp
T = Treeτ = Leafτ | Nodeτ (Treeτ )(Treeτ ).
Die minimalen Elemente sind Leafx für alle x ∈ τ. Weiterhin gilt
T1 < NodexT1 T2 und T2 < NodexT1 T2 für alle x ∈ τ und T1 , T2 ∈
T.
30
2.3 Transformation
2.3 Transformation
2.3.1 Fold-Unfold-Methode
Definition 2.6 (Fold-Unfold-Methode)
(i) Definition: Eine neue Funktionsgleichung wird eingefügt, deren
linke Seite keine Spezialisierung einer bereits existierenden Funktionsgleichung sein darf.
(ii) Instanz: Eine spezialisierte Funktionsgleichung wird eingefügt, indem in einer bereits existierenden Funktionsgleichung für Variablen Ausdrücke einsetzt.
(iii) Unfold: Eine neue Funktionsgleichung wird eingefügt, indem in
einer bereits existierenden Funktionsgleichung ein Funktionsaufruf durch den definierenden Ausdruck ersetzt wird.
(iv) Fold: Eine neue Funktionsgleichung wird eingefügt, indem in einer bereits existierenden Funktionsgleichung ein Ausdruck durch
einen Funktionsaufruf ersetzt wird.
(v) Abstraktion: Eine neue Funktionsgleichung wird eingefügt, indem
in einer bereits existierenden Funktionsgleichung lokale Definitionen eingeführt werden.
(vi) Gesetze: Eine neue Funktionsgleichung wird eingefügt, indem (algebraische) Gesetze auf die rechte Seite einer bereits existierenden
Funktionsgleichung angewendet werden.
Beispiel 2.7 Für eine Liste ganzer Zahlen soll der Mittelwert berechnet
werden.
avg l = (sum l) ‘div‘ (length l)
Unfold
avg l = (foldr (+) 0 l) ‘div‘ (sum (map (const 1) l))
Unfold
avg l = (foldr (+) 0 l) ‘div‘ (foldr (+) 0 (map (const 1) l))
Abstraktion
avg l = x ‘div‘ y
31
2 Haskell
where (x,y) = (foldr (+) 0 l,foldr (+) 0 (map (const 1) l))
Definition
accum l = (foldr (+) 0 l,foldr (+) 0 (map (const 1) l))
Gesetze
accum l = (foldr (+) 0 l,foldr (⊕) 0 l)
where x⊕n = 1+n
Gesetze
accum l = foldr () (0,0) l
where x(m,n) = (x+m,1+n)
2.3.2 Bird-Meertens-Formalismus
Theorem 2.8 (Dualitätssatz)
(i) Erster Dualitätssatz:
foldl f e = foldr f e
falls f eine assoziative Operation mit neutralem Element e ist.
(ii) Zweiter Dualitätssatz:
foldl f e = (foldr (flip f) e).reverse
(Beachte: Es gilt flip.flip = id und reverse.reverse = id.)
Beispiel 2.9 Wegen id = foldr (:) [] folgt aus dem zweiten Dualitätssatz
reverse = id.reverse = (foldr (:) []).reverse = foldl (flip (:)) []
Satz 2.10 Fold-Fusion:
f.(foldl g e) = foldl h (f e)
für f.g x y = h.f x y und
f.(foldr g e) = foldr h (f e)
für f.g x y = (flip ((flip h).f)) x y
32
2.3 Transformation
Theorem 2.11 (Bird-Meertens-Formalismus)
(i) Map-Distributivität:
(map f).(map g) = map (f.g)
(ii) Scan-Lemma:
(map (foldl f e)).inits = scanl f e
(map (foldr f e)).tails = scanr f e
(iii) Map-Promotion:
(map f).concat = concat.(map (map f))
(iv) Fold-Promotion:
(foldl n e).concat = (foldl n e).(map (foldl n e))
falls n eine assoziative Operation mit linksneutralem Element e und
(foldr o e).concat = (foldr o e).(map (foldr o e))
falls o eine assoziative Operation mit rechtsneutralem Element e ist.
(v) Fold-Map-Fusion:
(foldl f e).(map g) = foldl (flip ((flip f).g)) e
(foldr f e).(map g) = foldr (f.g) e
(vi) Fold-Scan-Fusion:
(foldl ⊕ 0).(scanl 1) = <<.(foldl ⊗ (0 ⊕ 1,1))
mit x << y = x und (x,y) ⊗ z = (x ⊕ (y z),y z)
(vii) Fold-Fold-Fusion (Horner):
(foldl ⊕ 0).(map (foldl 1)).tails = foldl ⊗ 1
mit x ⊗ y = (x y) ⊕ 1 falls rechtsdistributiv über ⊕ und 0
linksneutrales Element von ⊕ ist.
33
2 Haskell
2.4 Monaden
Definition 2.12 (Monade)
Eine Monade ist ein Typkonstruktor M zusammen mit zwei polymorphen Funktionen
unit :: a -> M a
(∗) :: M a -> (a -> M b) -> M b
sodass folgende drei Gleichungen gelten:
(i)
m ∗ unit = m
(ii)
(unit a) ∗ f = f a
(iii)
(m ∗ f) ∗ g = m ∗ (f ~ g)
Für einen Ausdruck der Form
m ∗ (\a -> n)
schreiben wir äquivalent auch
let a = m in n
34
2.4 Monaden
Satz 2.13 Für die Operation
(~) :: (a -> M b) -> (b -> M c) -> a -> M c
(f ~ g) a = (f a) ∗ g
gelten die folgenden drei Gesetze:
(i)
f ~ unit = f
(ii)
unit ~ f = f
(iii)
(f ~ g) ~ h = f ~ (g ~ h)
und es gilt
m ∗ f = (id ~ f) m
Beispiel 2.14
(i) Identitätsmonade:
type M a = a
unit a = a
a ∗ f = f a
f ~ g = g.f
map f a = f a
join a = a
(ii) Listenmonade:
type M a = [a]
unit a = [a]
[] ∗ f = []
(h:t) ∗ f = (f h) ++ (t ∗ f)
m ∗ f = concat.map f m
f ~ g = concat.(map g).f
map = map
join = concat
35
2 Haskell
(iii) Ausgabemonade:
type M a = (a,String)
unit a = (a,“ “)
m ∗ f = (b,s ++ s’) where { m = (a,s), f a = (b,s’) }
(f ~ g) a = (c,s ++ s’) where { f a = (b,s), g b = (c,s’) }
map f m = (f a,s) where m = (a,s)
join m = (a,s ++ s’) where m = ((a,s’),s)
(iv) Zustandsmonade:
type M a = State -> (a,State)
unit a = \s -> (a,s)
m ∗ f = \s -> f a s’ where m s = (a,s’)
(f ~ g) a = \s -> g b s’ where f a s = (b,s’)
map f m = \s -> (f a,s’) where m s = (a,s’)
join m = \s -> m’ s’ where m s = (m’,s’)
36
2.4 Monaden
Satz 2.15 Für die Operationen
map :: (a -> b) -> M a -> M b
map f m = m ∗ (unit.f)
und
join :: M (M a) -> M a
join m = m ∗ id
gelten die folgenden sieben Gesetze:
(i)
map id = id
(ii)
(map f).(map g) = map (f.g)
(iii)
(map f).unit = unit.f
(iv)
(map f).join = join.(map (map f))
(v)
join.unit = id
(vi)
join.(map unit) = id
(vii)
join.(map join) = join.join
Theorem 2.16 Ein Typkonstruktor M ist genau dann eine Monade, wenn
es Operationen unit, map und join gibt, die die sieben Gesetze aus dem
vorigen Satz erfüllen. Weiterhin gilt
x ∗ f = join.map f x
37
2 Haskell
38
Literaturverzeichnis
[Bar84] B ARENDREGT, H. P.: The Lambda Calculus: Its Syntax and Semantics (Studies in Logic and the Foundations of Mathematics). Revised
Edition. Elsevier Science, 1984. – ISBN 0444875082
[Bar91] B ARENDREGT, H. P.: Lambda Calculi with Types. 1991
39
Literaturverzeichnis
40
Index
?:τ, 18
A :?, 18
A:τ?, 18
CL-Kombinator, 15
CL-Term, 14
Λ-Hülle, 7
α-Konvertibilität, 5
β-Normalform, 8
β-Reduktion, 5
η-Reduktion, 5
λ-Kalkül, 5
λ-Term, 3
geschlossener, 4
λ-definierbar, 12
µ-Rekursion, 13
µ-rekursive Funktion, 13
ρ-Kontraktum, 7
ρ-Konvertibilität, 7
ρ-Redex, 7
ρ-Reduktion, 7
ξ-Regel, 5
äquivalent
syntaktisch, 3
C HURCH -R OSSER-Theorem
Erstes, 9
Zweites, 10
C HURCH-Zahlen, 7
Abstraktion, 3
algebraischer Datentyp, 29
Applikation, 3
Basislemma, 17
Bird-Meertens-Formalismus, 33
Curry-Howard-Isomorphismus, 22
Dualitätssatz, 32
Eindeutigkeitslemma, 19
Erstes C HURCH -R OSSER-Theorem,
9
Fixpunktkombinator, 18
Fold-Unfold-Methode, 31
freie Variable, 4
gebundene Variable, 4
Generierungslemma, 17
geschlossener λ-Term, 4
Grundfunktion, 12
Kombinator, 4
Komposition, 12
konvertierbar, 5
LI-Reduktion, 9
LO-Reduktion, 9
Monade, 34
Normalisierungstheorem, 10
numerisch, 12
primitiv-rekursive Funktion, 12
primitive Rekursion, 12
Reduktion
41
Index
LI-, 9
LO-, 9
schwache Normalform, 14
schwache Reduktion, 14
Substitution, 5
Substitutionslemma, 5, 17
syntaktisch äquivalent, 3
Teilterme, 4
Typaussage, 17
Typbewohntheitsproblem, 18
Typerhaltungstheorem, 18
Typisierbarkeitsproblem, 18
Typprüfungsproblem, 18
Typumgebung, 16
Variable, 3
freie, 4
gebundene, 4
wohlfundierte Induktion, 29
wohlfundierte Menge, 29
Wohltypung, 17
Zweites C HURCH -R OSSER-Theorem,
10
42
Herunterladen