Was bisher geschah I Deklarative vs. imperative Programmierung I Deklarative Programmierung Funktionale Programmierung in Haskell: I Algebraische Datentypen I Pattern Matching I (eingeschränkte) Polymorphie, Typklassen I Rekursive Datentypen: Peano-Zahlen, Listen, binäre Bäume I Rekursive Funktionen I strukturelle Induktion Funktionen als Daten bisher: f :: Int -> Int f x = 2 * x + 5 äquivalent: Lambda-Ausdruck f = \ x -> 2 * x + 5 Lambda-Kalkül: Alonzo Church 1936, Henk Barendregt 1984, ... Funktionsanwendung: ( \ x -> B ) A = B [ x := A ] ist nur erlaubt, falls keine in A freie Variable durch ein λ in B gebunden wird. Der Lambda-Kalkül . . . als weiteres Berechnungsmodell, (vgl. Termersetzungssysteme, Turingmaschine, Random-Access-Maschine) Syntax (induktive Definition): Die Menge der Lambda-Terme Λ( ) mit Variablen aus X X ist IA: jede Variable ist ein Term: v ∈ X ⇒ v ∈ Λ(X) IS: Applikation , Funktionsanwendung: Für alle F ∈ Λ( ), A ∈ Λ( ) gilt (FA) ∈ Λ( ) Abstraktion , Funktionsdefinition: Für alle v ∈ , B ∈ Λ( ) gilt (λv .B) ∈ Λ( ) X X X X X Semantik: eine Relation →β auf Λ( ) (vgl. →R für Termersetzungssystem R) X X Freie und gebundene Variablen(vorkommen) X X I Das Vorkommen von v ∈ an Position p in Term t ∈ Λ( ) heißt frei, wenn „darüber kein λv . . . . steht“ I Definition (durch strukturelle Induktion): fvar(t) = Menge der in t frei vorkommenden Variablen I Eine Variable x heißt in A gebunden, falls A einen Teilausdruck λx.B enthält. I bvar(t) = Menge der in t gebundenen Variablen Beispiele: I fvar(x(λx.λy .x)) = {x}, I bvar(x(λx.λy .x)) = {x, y } Semantik des Lambda-Kalküls X Relation →β auf Λ( ) (ein Reduktionsschritt) Es gilt t →β t 0 , falls I I I ∃p ∈ Pos(t), so daß t[p] = (λx.B)A mit bvar(B) ∩ fvar(A) = ∅ t 0 = t[p := B[x := A]] dabei bezeichnet B[x := A] ein Kopie von B, bei der jedes freie Vorkommen von x durch A ersetzt ist Ein (Teil-)Ausdruck der Form (λx.B)A heißt Redex. (Dort kann weitergerechnet werden.) Ein Term ohne Redex heißt Normalform. (Normalformen sind Resultate von Rechnungen.) Relation →α : gebundene Umbenennung Lambda-Terme: verkürzte Notation I Applikation als links-assoziativ auffassen, Klammern weglassen: (. . . ((FA1 )A2 ) . . . An ) ∼ FA1 A2 . . . An Beispiel: ((xz)(yz)) ∼ xz(yz) I geschachtelte Abstraktionen unter ein Lambda schreiben: λx1 .(λx2 . . . . (λxn .B) . . . ) ∼ λx1 x2 . . . xn .B Beispiel: λx.λy .λz.B ∼ λxyz.B Funktionen höherer Ordnung Funktionen als Argument von Funktionen Beispiel: twice :: (a -> a) -> a -> a twice f x = f (f x) Anwendung: I double hat den Typ Int -> Int I twice double hat den Typ Int -> Int I twice double 3 hat den Typ Int und den Wert ? I \x -> 2 * x + 1 hat den Typ Int -> Int twice (\x -> 2 * x + 1) hat den Typ Int -> Int I I twice (\x -> 2 * x + 1) 3 hat den Typ Int und den Wert ? I succ 0, twice succ 0, twice twice succ 0 I twice (^2) 3, twice twice (^2) 3 I Typ von twice twice ? Typ von twice twice twice ? Funktionen höherer Ordnung – Beispiele I punktweise Summe zweier Funktionen: fsum :: (a -> Int) -> (a -> Int) -> (a -> Int) fsum f g x = (f x) + (g x) fsum f g = \x -> (f x) + (g x) Beispiele: I I I fsum (*2) (+1) 4, fsum len head [ 2 .. 5 ] Komposition von Funktionen: (.) :: (a -> b) -> (b -> c) -> (a -> c) (f . g) x = f (g x) (f . g) = \ x -> f (g x) Beispiele: I I ( ( \ x -> x * 2 ) . len ) "foo" suchbaum = sortiert . inorder