Funktionale Programmierung Interpreter (Hilfsfunktionen) -- Berechnet die Liste der gebundenen Variablen boundList :: Expr -> [String] boundList (Var x) = [] boundList (Lambda x e) = x : (boundList e) boundList (App e1 e2) = (boundList e1) ++ (boundList e2) Prof. Dr. Margarita Esponda Funktionale Programmierung Interpreter (Hilfsfunktionen) -- Berechnet die Menge FV (Freie Variablen) freeList :: Expr -> [String] -> [String] freeList (Var x) bound | elem x bound = [] | otherwise = [x] freeList (Lambda x y) bound = freeList y ( x : bound ) freeList (App x y) bound = (freeList x bound) ++(freeList y bound) Prof. Dr. Margarita Esponda Funktionale Programmierung Definition der Ersetzungsfunktion Für beliebige Ausdrücke E1, E2 und eine Variable x, definieren wir E2[E1\x] als die Ersetzung aller freien Vorkommen der Variable x durch E1 in E2 mit eventuellen Umbenennungen von gebundenen Variablennamen, um Namens-Konflikte zu vermeiden. a) x[E1\x] ≡ E1 b) y[E1\x] ≡ y für alle Variablen y ≠ x c) (E2E3)[E1\x] ≡ E2 [E1\x] und E3 [E1\x] d) (λx.E2)[E1\x] ≡ λx.E2 e) (λy.E2)[E1\x] ≡ λy.E2 wenn x∉FV(E2) f) (λy.E2)[E1\x] ≡ λy.(E2 [E1\x]) wenn x∈FV(E2) und y∉FV(E1) g) (λy.E2)[E1\x] ≡ λz.(E2[E1\x][z\y]) wenn x∈FV(E2) und y∈FV(E1) In e), f) und g) ist y ≠ x. In g) wird die erste Variable gewählt, die ∉FV(E1E2) ist. Prof. Dr. Margarita Esponda Funktionale Programmierung Reduktionsstrategien in λ-Ausdrücken ((λ x.x) (λ y.yz)) ((λ a.a) (λ b.bw)) (λ y.yz) ((λ a.a) (λ b.bw)) ((λ a.a) (λ b.bw)) z (λ b.bw)z zw Prof. Dr. Margarita Esponda (λ y.yz) (λ b.bw) (λ b.bw)z zw ((λ x.x) (λ y.yz)) (λ b.bw) (λ y.yz) (λ b.bw) (λ b.bw)z zw Funktionale Programmierung Reduktionsstrategien in λ-Ausdrücken Die Call-by-Name Auswertungsstrategie reduziert immer den am weitesten oben und am weitesten links stehenden Redex und sonst nichts. (λ x. E1 ) E2 ⇒β E1 [ E2 \ x ] Die Call-by-Value Auswertungsstrategie reduziert die Lambda Ausdrücke nur, wenn die Argumente wiederum λ-Ausdrücke oder Variablen sind. (λ x. E1 ) v ⇒β E1 [ v \ x ] mit v = λ-Abstraktion oder Variable Die Auswertung geht von innen nach außen und von links nach rechts. Prof. Dr. Margarita Esponda Funktionale Programmierung Call-by-Name Reduktionsstrategie oder Normalordnung-Reduktion ((λ x.x) (λ y.yz)) ((λ a.a) (λ b.bw)) (λ y.yz) ((λ a.a) (λ b.bw)) ((λ a.a) (λ b.bw)) z (λ b.bw)z zw Prof. Dr. Margarita Esponda (λ y.yz) (λ b.bw) (λ b.bw)z zw ((λ x.x) (λ y.yz)) (λ b.bw) (λ y.yz) (λ b.bw) (λ b.bw)z zw Funktionale Programmierung Call-by-Name Probleme: (λ x. λ y.yxxz)(λ a.ya) ⇒ λ y.y(λ a.ya)(λ a.ya)z Teilausdrücke werden nicht mehr reduziert (λ y. λ z. z)((λ x.xx)(λ x.xx)) ⇒ λ z. z Call-by-Value Probleme: Prof. Dr. Margarita Esponda (λ y. λ z. z)((λ x.xx)(λ x.xx)) ⇒ Endlosschleifen! Funktionale Programmierung Interpreter (1. Version) eval :: Expr->Expr eval (Var x) = Var x eval (Lambda x exp) = (Lambda x exp) eval (App (Var x) exp) = (App (Var x) (eval exp)) eval (App (Lambda a e2) e1) = eval (subst a e1 e2) eval (App (App e2 e1) e3) | (evale21 == (App e2 e1)) = (App (App e2 e1) e3) | otherwise = eval (App evale21 e3) where evale21 = eval (App e2 e1) Prof. Dr. Margarita Esponda Funktionale Programmierung Interpreter (Ersetzungsfunktion) -- ersetzt alle Vorkommen von x in dem Lambda-Ausdruck des -- dritten Arguments mit dem Ausdruck exp. subst :: String -> Expr -> Expr -> Expr subst x exp (Var y) | x==y = exp | otherwise = Var y subst x exp (Lambda y z) | x==y = Lambda y z | (elem y (freeList exp [])) = subst x exp (rename y new (Lambda y z)) | otherwise = (Lambda y (subst x exp z)) where new = find_new_name ( (freeList exp []) ++ (freeList z []) ++ (boundList z) ) subst x exp (App y z) = App (subst x exp y) (subst x exp z) Prof. Dr. Margarita Esponda Funktionale Programmierung Interpreter (Hilfsfunktionen) -- Benennt die Variable y in den neuen Namen n um rename :: String -> String -> Expr -> Expr rename y n (Var x) | x==y = Var n | otherwise = Var x rename y n (Lambda x e) | x==y = (Lambda n (rename y n e)) | otherwise = (Lambda x (rename y n e)) rename y n (App e1 e2) = (App (rename y n e1) (rename y n e2)) Prof. Dr. Margarita Esponda Funktionale Programmierung Interpreter (Hilfsfunktionen) -- Ein neuer Variablenname wird gesucht. find_new_name :: [String] -> String find_new_name prohibited = head [ [u]|u<-['a'..'z'], not(elem [u] prohibited ) ] Prof. Dr. Margarita Esponda Funktionale Programmierung Anonyme Funktionen Anonym-Funktionen können in Haskell mit Hilfe von λ-Ausdrücken programmiert werden. Beispiele: fx = exp g x y = exp ------- f = \x → exp g = \x y → exp fact f = \n -> foldl (\x y -> x*y) 1 [1..n] = zipWith (\x y → x*x + y*y) h ls = map (\xs -> zip xs [1..]) ls h ["abc", "abc"] ⇒ [[('a',1),('b',2),('c',3)],[('a',1),('b',2),('c',3)]] für das schnelle Implementieren einfacher Hilfsfunktionen Prof. Dr. Margarita Esponda Funktionale Programmierung Anonyme Funktionen Beispiel: Wir können unseren Y-Operator in Haskell wie folgt definieren: fix rec = rec (fix rec) factorial = \r n -> if n==0 then 1 else ((*) n (r (n-1))) fibs = \r n -> if n<=1 then n else ((+) (r (n-1)) (r (n-2))) (fix factorial) 9 ⇒ 362880 Prof. Dr. Margarita Esponda Funktionale Programmierung Literatur A Tutorial Introduction to the Lambda Calculus. Raúl Rojas. http://www.inf.fu-berlin.de/lehre/WS03/alpi/lambda.pdf A Brief and Informal Introduction to the Lambda Calculus. Paul Hudak. Spring 2008. http://plucky.cs.yale.edu/cs201/lambda.pdf Prof. Dr. Margarita Esponda