Was bisher geschah Funktionale Programmierung (Haskell): I Algebraische Datentypen I strukturelle Induktion I Rekursionsschemata I Funktionen höherer Ordnung (z.B. map, fold, filter) I Lazy evaluation I Monaden (z.B. Maybe, List, IO) I Parser-Monade (Parsec) 184 Funktionale und logische Programmierung I funktionale Programmierung: LISP (John McCarthy, 1957) benutzerdefinierte Funktionen, definiert durch Gleichungen (Ersetzungsregeln) Rechnen = Normalform bestimmen Methode: Termersetzung I logische Programmierung: Prolog (Alain Colmerauer, 1972) benutzerdefinierte Relationen (Prädikate), definiert durch Schlussregeln (Implikationen). Rechnen = Schlussfolgerung (Widerspruch) ableiten Methode: prädikatenlogische Resolution 185 Wiederholung: Prolog-Syntax Regel (Klausel) a :- a1, ..., am. Bedeutung in Prädikatenlogik (der ersten Stufe) (∀X1 · · · ∀Xn ((a1 ∧ · · · ∧ am ) → a) wobei X1 , . . . Xn alle in a, a1 , . . . , an vorkommenden Variablen sind. Rumpf a1 ∧ . . . ∧ am , Kopf a Fakt Atom a. (positives Literal, Regel ohne Rumpf) Bedeutung in Prädikatenlogik (der ersten Stufe): ∀X1 · · · ∀Xn a, wobei X1 , . . . Xn alle in a vorkommenden Variablen sind. Zielklausel (Query, Anfrage) ?- a1, ..., an. Bedeutung in Prädikatenlogik (der ersten Stufe): (∀X1 · · · ∀Xn (a1 ∧ · · · ∧ am ) wobei X1 , . . . Xn alle in a1 , . . . , am vorkommenden Variablen sind. Variablennamen beginnen mit Großbuchstaben, Funktions- und Relationssymbole mit Kleinbuchstaben 186 Wiederholung: Prolog-Programme Programm P (Wissensbasis): endliche Menge von Fakten und Regeln, repräsentiert eine prädikatenlogische Formelmenge Φ, (repräsentiert eine prädikatenlogische Formel V ϕ = ψ∈Φ ψ) Beispiel: Programm P liest(paul,krimi). liest(bob,zeitung). liest(tina,arztroman). mag(tina,X) :- liest(X,krimi). repräsentiert die Formelmenge Φ = {l(p, k ), l(b, z), l(t, a), ∀x(l(x, k ) → m(t, x))} 187 Wiederholung: Prolog-Anfragen Zielklausel Atom repräsentiert eine prädikatenlogische Formel ψ Beispiel: ?- mag (tina,X). repräsentiert die Formel ψ = mag(tina, X ) 188 Wiederholung: Prolog-Auswertung Ausgewertet werden Paare (Φ, ψ) aus I Programm Φ I Zielklausel ψ (prädikatenlogische Darstellung von Programm und Anfrage) Antwort: Substitution θ mit Φ |= θ(ψ) (Prolog-Ausgabe: Grundinstanzen θ(ψ) der Zielklausel ψ) 189 Prolog: Bestimmung der Antworten I durch Lösung der Aufgabe: Für welche Substitutionen θ gilt Φ |= θ(ψ)? I durch Lösung der äquivalenten Aufgabe: Für welche Substitutionen θ ist die Formelmenge Φ ∪ ¬θ(ψ) unerfüllbar? I durch Lösung der äquivalenten Aufgabe: Für welche Substitutionen θ gilt Φ ∪ ¬θ(ψ) |= f ? I durch Bestimmung der Substitutionen θ, für die f aus Φ ∪ ¬θ(ψ) syntaktisch herleitbar ist. I durch prädikatenlogische Resolution mit festgelegter Auswertungsreihenfolge (SLD-Resolution) 190 Beispiel für Prolog-Auswertung Programm P: p(a,b). p(b,c). p(c,d). e(X,Y) :- p(X,Y). e(X,Y) :- p(X,Z), e(Z,Y). Zielklausel e(X , d) Prädikatenlogische Bedeutung: I Programm P: p(a, b), p(b, c), p(c, d), ∀X ∀Y (p(X , Y ) → e(X , Y )), Φ= ∀X ∀Y ∀Z (p(X , Z ) ∧ e(Z , Y ) → e(X , Y )) I Zielklausel ψ = e(X , d) I negierte Zielklausel ¬ψ = ¬e(X , d) I Problem ¬e(X , d), p(a, b), p(b, c), p(c, d), ∀X ∀Y (p(X , Y ) → e(X , Y )), {¬ψ} ∪ Φ = ∀X ∀Y ∀Z (p(X , Z ) ∧ e(Z , Y ) → e(X , Y )) 191 Datentypen für Prolog-Interpreter in Haskell I Funktions- und Prädikatsymbole Identifier (String) I Variablen Identifier (String) I Terme Term (Baum) I Atome (Identifier, [Term]) I Regelrümpfe Body ([Atom]) I Regeln (Atom, Body) Fakten (Atom, []) I Anfragen (Regeln mit leerem Kopf) Body I Programme [Regel] I Substitutionen Map s Term 192 Datentypen in Haskell data Term = App String [ Term ] | Var String data Atom = Atom String [ Term ] data Body = Body [Atom] data Rule = Fact Atom | Rule Atom Body data Query = Query Body data PQProg = PQ [Rule] Query Parser dafür im voriger Vorlesung (ähnlich in PParse.hs und Program.hs) 193 Wiederholung Unifikation Substitution: partielle Funktion θ : X → Term(Σ, X ), wobei keine Variable x, für welche θ(x) definiert ist, für ein y ∈ X in θ(y ) vorkommt, Notation: [x 7→ t1 , y 7→ t2 , . . .] Unifikator der Terme (Atome, Literale) s und t: Substitution θ mit θ(s) = θ(t) mgu(s, t) allgemeinster Unifikator der Terme (Atome, Literale) s und t: Unifikator θ für s und t, so dass zu jedem Unifikator σ für s und t eine Substitution ρ für s und t existiert, so dass gilt: σ(s) = ρ(θ(s)) (analog ggT zweier natürlicher Zahlen) 194 Beispiele I s = f (x, g(y )), t = f (g(z), z) Substitution σ(x) = g(g(f (a, a))), σ(y ) = f (a, a)), σ(z) = g(f (a, a)) ist Unifikator Substitution σ(x) = g(g(y )), σ(z) = g(y ) ist allgemeinster Unifikator I p(x), p(f (y )) Substitution σ(x) = f (f (a)), σ(y ) = f (a) ist Unifikator Substitution σ(x) = f (y ), σ(y ) = y ist allgemeinster Unifikator I p(f (a), g(x)), p(f (z), s(f (z))) 195 Substitutionen in Haskell Datentyp: type Substitution = Map Identifier Term Anwendung auf Term: apply :: Substitution -> Term -> Term apply sub t = case t of Var v -> case M.lookup v sub of Just t’ -> t’ Nothing -> t App f xs -> App f $ map ( apply sub ) xs Nacheinanderausführung: times times [ , , ] :: Substitution -> Substitution -> Substitution s t = M.unions chained s t s ‘without‘ M.keysSet t t ‘without‘ M.keysSet s (in Substitution.hs) 196 Wiederholung Unifikationsalgorithmus zur Bestimmung des mgu (sofern dieser existiert) Eingabe: Terme (Atome, Literale) s, t Ausgabe: (unifizierbar, mgu(s, t)), falls mgu(s, t) existiert, sonst nicht unifizierbar Algorithmus (rekursiv) : unifiziere(s, t) BF1 falls s, t Konstanten: falls s = t: (unifizierbar, mgu(s, t) = []), sonst nicht unifizierbar BF2 falls s Variable, t Konstante: [s 7→ t] in θ einfügen und auf alle rechten Seiten in θ anwenden BF3 falls s Variable, t = f (t1 , . . . , tn ): falls s nicht in t vorkommt: mgu(s, t) = [s 7→ t], sonst nicht unifizierbar RF falls s = g(s1 , . . . , sm ), t = f (t1 , . . . , tn ): falls m 6= n oder f 6= g: nicht unifizierbar sonst θ = unifiziere(s1 , t1 ), . . . , unifiziere(sn , tn ) 197 Beispiele allgemeinste Unifikatoren von 1. P(a, x), P(y , y ) 2. P(g(x), z), P(g(y ), g(z)) 3. P(g(x), y ), P(y , h(x)) 4. P(y , f (a, z)), P(b, f (a, b)) 5. P(y , f (x, y )), P(b, f (a, y )) 6. P(y , f (x, x)), P(b, f (a, y )) 198 Unifikation in Haskell mgu :: Term -> Term -> Maybe Substitution mgu s t | s == t = return $ M.empty mgu ( Var v ) t = do guard $ not $ S.member v $ variables t return $ M.fromList [ (v, t) ] mgu t ( Var v ) = mgu ( Var v ) t mgu ( App f xs ) ( App g ys ) = do guard $ f == g mgu_for_list xs ys mgu_for_list [] [] = return M.empty mgu_for_list (x:xs) (y:ys) = do sub1 <- mgu_for_list xs ys sub2 <- mgu ( apply sub1 x ) ( apply sub1 y ) return $ times sub1 sub2 (in Unify.hs) 199 Wiederholung: aussagenlogische Resolution Φ |= ψ gdw. leere Klausel (f) aus Φ ∪ {¬ψ} durch Resolution ableitbar Wiederholte Anwendung der Resolutionsregel {ψ ∨ p, ¬p ∨ η} |= ψ ∨ η Beispiele: I (¬p ∧ ¬q ∧ r ) ∨ (¬p ∧ ¬r ) ∨ (q ∧ r ) ∨ p allgemeingültig I {a ∨ b ∨ c, (a ∨ b) → d, ¬c ∧ e} |= d ∧ e 200 Grundresolution Idee: implizite Übersetzung in Aussagenlogik I Instanziierung aller Regeln. I Grundterme als Aussagenvariablen I Herbrand-Struktur. Unerfüllbarkeitstest durch aussagenlogische Resolution 201 Prädikatenlogische Resolution Berechnung einer prädikatenlogischen Resolvente der 0 : Klauseln l1 ∨ . . . ∨ ln } und l10 ∨ . . . ∨ lm I Variablenumbenennung (Klauseln haben keine gemeinsamen Variablen) I Bestimmung eines allgemeinsten Unifikators σ für ein Paar von Literalen li und ¬lj0 I Resolvente: σ(l1 ) ∨ . . . ∨ σ(li−1 )∨)σ(li+1 ) ∨ . . . ∨ σ(ln ) ∨ 0 ) ∨ σ(l 0 ) ∨ . . . ∨ σ(l 0 ) σ(l10 ) ∨ . . . ∨ σ(lj−1 m j+1 202 Beispiel Klauselmenge Φ = {P(x, b) ∨ P(a, y ) ∨ Q(x, f (y )), ¬P(z, w), ¬Q(w, z)} Resolution: positive Literale P(x, b), P(a, y ) negatives Literal ¬P(z, w) Substitution σ = [x 7→ a, y 7→ b, z 7→ a, w 7→ b] Resolvente Q(a, f (b)) ∨ ¬Q(b, a) 203 SLD-Resolution für Mengen von Hornklauseln Auswahl der angewendeten Regeln in einer festen Reihenfolge: I erste anwendbare Regel im Programm, I in jedem Schritt entsteht eine Hornklausel I neu erzeugte Regel sofort angewenden I zuerst das erste Rumpf-Literal resolvieren I Auswahl nur für dessen Resolutions-Partner (Suchbaum, meist Tiefensuche) (immer Substitution β mitführen) 204 Suche in Haskell Modellierung von Suche / Nichtdeterminismus in Haskell: Listen-Monade Liste von Resultaten, wie z.B. bei Berechnung aller Permutationen einer Liste import Data.List perm :: Eq a => [a] -> [[a]] perm [] = [[]] perm xs = do x <- xs ys <- perm (delete x xs) return $ (x : ys) 205 Prolog-Interpreter query :: [ P.Clause ] -> Int -> Terms -> [ (Substitution, Int) ] query cs u0 [] = do return ( M.empty, u0 ) query cs u0 (t : ts) = query_apply cs ( single cs u0 t ) ts Nichtdeterminismus / Suche nach anwendbarer Regel: single :: [ P.Clause ] -> Int -> Term -> [ (Substitution, Int) ] single cs u0 t = do c0 <- cs let c = rename u0 c0 ufs = do sub <- maybeToList $ mgu t $ P.head c return ( sub, u0 + 1 ) ( sub, u1) <- query_apply cs ufs $ P.body c let vs = S.unions $ map variables $ P.head c : P.body c return ( cleanup vs sub, u1 ) (in Eval.hs) 206 Ideales und Reales Prolog wie hier definiert (ideal): I Semantik ist deklarativ I Reihenfolge der Regeln im Programm und Atome in Regel-Rumpf beeinflusst Effizienz, aber nicht Korrektheit reales Prolog: I cut (!) zum Abschneiden der Suche I I green cut: beeinflusst Effizienz red cut: ändert Semantik merke: cut ≈ goto, grün/ rot schwer zu unterscheiden I Regeln mit Nebenwirkungen (u. a. für Ein/Ausgabe) für beides: keine einfache denotationale Semantik 207