– Regeln sterblich(X) :- mensch(X). vernetzt(X) :- verbunden(X,Y), vernetzt(Y). – Anfragen |?- sterblich(sokrates). |?- bruder(jo, X). ... G. Görz, FAU, Inf.8 12–1 G. Görz, FAU, Inf.8 Terme und Formeln 12–3 Terme und Unifikation Ein etwas genauerer Blick auf die Sprachelemente von PROLOG: Beispiel: Axiomatisierung der Addition mit Nachfolgerfunktion • Terme Variablen: X, . . . Anonyme Variable: Atome: tim, ’hello world’, . . . Zahlen: 4711, 5.7E-3, . . . Funktionsterme: f(X), g(h(blah, Y)), . . . add(0,Y,Y). add(succ(X),Y,succ(Z)) :- add(X,Y,Z). Der atomare Term 0 repräsentiert die Zahl 0, der Term succ(0) die 1, etc. • Formeln – Fakten mensch(adam). liebt(X, eva). geburtstag(jo, datum(11,november,1980)). G. Görz, FAU, Inf.8 ... succ ist ein uninterpretiertes Funktionssymbol; Term succ(0) kann nicht zu dem Term 1 ausgewertet (reduziert) werden. Die einzige Beziehung zwischen diesen Termen und den Zahlen ist die Bedeutungsrelation, die der Programmierer “zuschreibt”. ... 12–2 G. Görz, FAU, Inf.8 12–4 Beispielanfragen: Dieses Ziel ist mit der Einheitsklausel add(0,Y,Y) unifizierbar mit der Substitution Y 2 = succ(succ(0)), Z 1 = Y 2 ?- add(0,succ(0), Result). Antwort: Result = succ(0) yes und die Ausführung terminiert erfolgreich. Somit: Result = = = = ?- add(succ(succ(0)),succ(succ(0)),Result). Result = succ(succ(succ(succ(0)))) yes succ(Z) succ(succ(Z_1)) succ(succ(Y_2)) succ(succ(succ(succ(0)))) Ausführung für zweites Beispiel: Unifikation der Anfrage mit add(succ(X),Y,succ(Z)) ist erfolgreich mit X = succ(0), Y = succ(succ(0)), Result = succ(Z) und transformiert beide Formeln in add(succ(succ(0)),succ(succ(0)),succ(Z)). Anmerkung : Die in Prolog benutzte Variante der Resolutionsregel (spezielle Strategie) heisst SLD-Resolution: “Linear resolution for Definite clauses with Selection function”. G. Görz, FAU, Inf.8 G. Görz, FAU, Inf.8 12–5 12–7 Unifikation und der “Occurs Check” succ-Beispiel (Forts.) Schrittweise: Wenn eine Variable X mit einem Term T unifiziert werden soll, ist für das Gelingen der Unifikation entscheidend, dass X nicht in T vorkommt. Das ursprüngliche Ziel kann nicht mit der ersten, aber mit der zweiten Klausel unter der genannten Substitution unifiziert werden. Normalerweise wird in PROLOG dieser Test, der “Occurs Check”, aus Effizienzgründen weggelassen. Damit: Keine volle Unifikation! Damit wird der Rumpf der zweiten Klausel zu add(succ(0),succ(succ(0)),Z). Beispiel: Der Matcher erlaubt eine Passung von f(X,X) mit f(Y,g(Y)) und bindet X an g(X), ohne die Zirkularität zu bemerken. Diese kann wiederum mit dem Kopf der zweiten Klausel im Programm unifiziert werden und ergibt (mit Variablenumbenennung) die Substitution X 1 = 0, Y 1 = succ(succ(0)), Z = succ(Z 1) In den meisten PROLOG-Systemen kann der Occurs Check über ein Flag eingeschaltet und damit die volle Unifikation ermöglicht werden — allerdings um den Preis einer beträchtlichen Verlangsamung der Berechnung (Rekursiver Abstieg in Termen!). Eingesetzt in den Prozedurrumpf: add(0,succ(succ(0)),Z 1). G. Görz, FAU, Inf.8 12–6 G. Görz, FAU, Inf.8 12–8 Beispiel: Die dreistellige Relation add entspricht einer Axiomatisierung der Addition durch die Funktion + in einer Logik mit Gleichheit: Funktionen in PROLOG Verfügt man über einen Logikkalkül mit Gleichheit zwischen Termen als Grundbegriff, wird durch die Reduzierbarkeit von Termen auf andere eine leistungsfähige Technik verfügbar, um Schlüsse über Funktionen durchzuführen. Im Logikkalkül wären Gleichheitsaxiome erforderlich, um Beweisprozeduren für die Gleichheit als Grundlage für funktionale Berechnung nutzen zu können (analog zu Hornklausel-Beweisprozeduren als Grundlage für relationale Berechnung). 0 + x = x succ(x) + y = succ(x + y) Aber: Von den Gleichheitsaxiomen bleibt (aus Effizienzgründen) in PROLOG nur die Reflexivität X = X (Standard-Infixoperator). Konsequenz: Es ist nicht möglich, zu schließen, ob zwei Terme dasselbe Objekt bezeichnen! Terme wie f(a) können nicht ausgewertet werden! Problem: Allgemeine Beweisprozeduren für Logik mit Gleichheit sind nicht effizient genug für Logikprogrammiersysteme (Kontrollproblem). Versuch: Repräsentation durch Relationen? G. Görz, FAU, Inf.8 12–9 G. Görz, FAU, Inf.8 Repräsentation von Funktionen durch Relationen Die PROLOG-Sicht von Funktionen Funktionen sind Konstruktoren: Jeder variablenfreie Term wird als Bezeichnung eines Elements in der Domäne angesehen. Funktionssymbole dienen zur (notationellen) Konstruktion neuer Elemente aus gegebenen. (Analogie: cons in Scheme) Die Beobachtung, dass Funktionen in einer Domäne durch Relationen repräsentiert werden können, war ein entscheidender Schritt, die Logikprogrammierung praktikabel zu machen. Nachteile: 1. Verlust der Eindeutigkeit von Funktionswerten! In bestimmten Fällen, wenn die relationale Definition einer Funktion nur ein Ergebnis für jede Eingabe liefert (add), kann Eindeutigkeit erreicht werden — nur kontingente Eigenschaft. 2. Relationale Syntax erfordert Einführung von Hilfsvariablen (erschwerte Lesbarkeit). G. Görz, FAU, Inf.8 12–11 Zusammengesetzte Terme spielen in PROLOG die Rolle von Record-Strukturen (einzige Datenstrukturen in PROLOG!). Die Unifikation spielt damit eine doppelte Rolle: 1. Selektion durch Auswahl/ Aufnahme der Argumente von Funktionen; 2. Konstruktion durch Instantiierung von Variablen mit komplexen Termen. Terme mit Variablen stehen für partiell spezifizierte Datenstrukturen (Variable als Platzhalter). 12–10 G. Görz, FAU, Inf.8 12–12 Zur Arithmetik in PROLOG Rekursion und Iteration Prolog sieht für arithmetische Terme Infix-Notation vor. Rekursion am Beispiel der Fakultätsfunktion: Funktionen: N+N , N-N , -N , N*N , N/N , I//I , I rem I , I mod I sowie bitweise Operationen Relationen: =:= , =\= , < , =< , > , >= fac(0,1). fac(N,V) :N > 0, N1 is N-1, fac(N1,V1), V is N*V1. Das is/2-Prädikat (/-Notation: Stelligkeit) ist als arithmetische Funktion registriert und erzwingt Auswertung arithmetischer Ausdrücke rechts, z.B. X is 4*2 . Arithmetische Relationen erzwingen die Auswertung arithmetischer Ausdrücke auf beiden Seiten. G. Görz, FAU, Inf.8 [debug] T Call: T Call: T Call: 12–13 Operatoren Funktionsterme können in Präfix-, Infix- und Postfix-Notation geschrieben werden. Festzulegen: Vorrang und Assoziativität der Operatoren Priorität 500 400 200 200 Assoziativität yfx yfx xfy fy Ein Trace: Operator + * / ** - ?- fact(3,X). (8) fact(3, _G360) (9) fact(2, _G363) (10) fact(1, _G366) G. Görz, FAU, Inf.8 T T T T T Call: Exit: Exit: Exit: Exit: X = 6 12–15 (11) fact(0, _G369) (11) fact(0, 1) (10) fact(1, 1) (9) fact(2, 2) (8) fact(3, 6) Iterative Variante (Endrekursion! Analog auch für Baumrekursion) fac_it(N,V) :- fac_it(N, 1, V). fac_it(0,V,V). fac_it(N,V0,V) :N > 0, V1 is V0*N, N1 is N-1, fac_it(N1,V1,V). Benutzerdefinierte Operatoren: Die Direktive op definiert/modifiziert Operator mit Namen Atom :- op(Prio, Assoc, Atom). G. Görz, FAU, Inf.8 12–14 G. Görz, FAU, Inf.8 12–16 Gleichheitsprädikate Differenzlisten • = Unifikationsprädikat (Vergleich von Termen) Erfolg, wenn es seine Argumente unifizieren kann, sonst Scheitern In manchen Fällen ist es zweckmäßig, die Darstellung durch Differenzlisten zu verwenden: Sie werden konstruiert durch ein Paar von Listenstrukturen, in denen die eine ein Suffix der anderen ist. • \= Negation des Unifikationsprädikats • Jede Liste in ein suffix von sich selbst. • == Identitätsprädikat • Ist die Liste von der Form [Head|Tail], so ist jeder Suffix von Tail ein Suffix der ganzen Liste. • \== Negation des Identitätsprädikats • =:= Arithmetisches Gleichheitsprädikat Erfolg, wenn seine Argumente zur selben Zahl evaluieren, sonst Scheitern D.h., die Beziehung zwischen Listen und ihren Suffixen ist die reflexive transitive Hülle der Relation zwischen der Liste und ihren Resten. Konstruktion von Differenzlisten mit dem Infix-Operator “-”: Eine Differenzliste List-Suffix stellt die Folge der Elemente in List bis auf jene in Suffix dar. • =\= Arithmetisches Ungleichheitsprädikat G. Görz, FAU, Inf.8 12–17 G. Görz, FAU, Inf.8 12–19 Beispiel: Die Liste [1,2,3] kann durch folgende Differenzlisten dargestellt werden: [1,2,3,4]-[4], [1,2,3]-[], [1,2,3|X]-X, etc. Darstellung von Listen in PROLOG Der Listenkonstruktor: “.” (= ˆ cons). Listen sind PROLOG-Terme! Konkatenation wird durch Differenzlisten einfach: conc dl(Front-Back1, Back1-Back2, Front-Back2) [] leere Liste [X|Y] Liste mit Kopf X und Rest Y Beispiele: [Head|Tail] [a,b|X] Liste mit Sequenz a,b, d.h. mit [a,b] als Kopf Explizite Verwendung des Kontruktors im Beispiel: .(a,.(b,[])) == [a,b]. PROLOG-Programm, das die induktive Definition von Listen wiedergibt: list([]). list([Head|Tail]) :- element(Head), list([Tail]). G. Görz, FAU, Inf.8 12–18 G. Görz, FAU, Inf.8 12–20 Anwendung: Beispiele für Rekursion über Listen Generelle Spezifikation von Sortierung Element-Relation sort(Old,New) :- perm(Old,New), ordered(New). member(X,[X|Xs]). member(X,[Y|Ys]) :- member(X,Ys). Old und New mögen Listen bezeichnen. Trace Wie kommt man von dieser hohen Abstraktionsebene zu einer konkreten Spezifikation? | ?- member(2,[1,2,3]). => | ?- member(X,[1,2,3]). => | ?- member(2,X). => yes X = 1; X = 2; X = 3 X = [2|_G822]; X = [_G821,2|_G824];... Zusammenhängen zweier Listen Notwendig: Definition der Prädikate perm und ordered. Wünschenswert: Prozedurale Verzahnung der beiden Prädikate bei der Ausführung. append([],Ys,Ys). append([X|Xs],Ys,[X|Zs]) :- append(Xs,Ys,Zs). G. Görz, FAU, Inf.8 12–21 G. Görz, FAU, Inf.8 Berechnungen mit partiell definierten Objekten 12–23 Definition des Sortierprogramms Unterbestimmte Werte werden durch ungebundene Variablen repräsentiert (“unbound Variable” ist kein Fehler!) Logik-orientierte Programmierung gestattet die Verarbeitung partieller “Information”. delete(X,[X|L],L). delete(X,[Y|L],[Y|Z]) :- delete(X,L,Z). Beispiel: halb1(x) :- X = struct(3,_). halb2(x) :- X = struct(_,5). | A | A ordered([]). ordered([X]). ordered([X|[Y|L]]) :- X<Y, ordered([Y|L]). ?- halb1(A). = struct(3,_G484) ?- halb1(A),halb2(A). = struct(3,5) G. Görz, FAU, Inf.8 perm([],[]). perm(L,[X|Y]) :- delete(X,L,L2), perm(L2,Y). Hinweis: Als Subjunktionen lesen! 12–22 G. Görz, FAU, Inf.8 12–24 Wegen des inhärenten Nichtdeterminismus können bei der Konstruktion einer Permutation die Elemente der ursprünglichen Liste in beliebiger Reihenfolge gelöscht werden. Welches Element gelöscht wird, hängt jedesmal von der Auswahl einer der beiden delete-Klauseln ab. Siehe folgende Abbildung: • Nicht-logische Erweiterungen (⇒ Meta-Programmierung) Erfüllt man z.B. die Bedingung delete(X,L,L2) durch Verwendung der ersten Klausel, wird X an den Kopf und L2 an den Rest von L gebunden. Bei Wahl der zweiten Klausel und danach der ersten würde das ursprüngliche X an das zweite Element von L gebunden und L2 an den Rest von L ohne das zweite Element. G. Görz, FAU, Inf.8 Kontrollkonstrukte und andere Erweiterungen von PROLOG 12–25 – Kontrollkonstrukte: true , fail , Cond -> Act : Else, call(G) erzwingt Beweis von G Cut (!) (s.u.) und weitere – Negation-as-Failure (“not provable”): \+ Goal :- call(Goal) -> fail; true. – “All-Solutions”-Prädikate: setof(Term, Goal, S) u.a. – Manipulation von Termen: var(X), atomic(X) u.a., Term =.. List. ⇒ “programs are data, also in PROLOG” – Explizite Manipulation der Datenbasis: assert(T), retract(T) G. Görz, FAU, Inf.8 12–27 • Damit Konstruktion von Meta-Interpretern, z.b. auch zur Einbettung objekt-orientierter Programmierung Sortierprogramm (2) • Spracherweiterungen, z.B. um Modaloperatoren • Constraint Logic Programming: Kombination mit einem Constraint Solver zur Lösung von (Un-) Gleichungssystemen • Kombination mit anderen Programmierstilen (funktional, objekt-orientiert) in neuen Programmiersprachen G. Görz, FAU, Inf.8 12–26 G. Görz, FAU, Inf.8 12–28 Der Cut — Explizite Steuerung des Backtracking “Rote Cuts”: Eine mangelhafte Programmiertechnik Wenn Cuts verwendet werden, um explizite Bedingungen wegzulassen, spricht man von “roten Cuts”. Der Cut ! in einer allgemeinen Klausel A ← B1, . . . , Bk , !, Bk+2 . . . , Bn C Wenn das aktuelle Ziel G mit dem Kopf von C unifiziert und B1, . . . , Bk erfolgreich sind, hat der Cut folgenden Effekt: Schlechtes Beispiel: minimum(X,Y,X) :- X≤Y, !. minimum(X,Y,Y). • Das Programm ist festgelegt auf die Wahl von C zur Reduktion von G; alternative Klauseln für A, die mit G unfizieren könnten, werden ignoriert. Was der Autor ausdrücken wollte: Wenn X ≤ Y, dann ist das Minimum X. Andernfalls ist das Minimum Y und ein weiterer Vergleich zwischen X und Y ist überflüssig. • Falls Bi für i > k scheitert, geht Backtracking nur bis zum ! zurück. Aber: Obiges Programm ist erfolgreich mit dem Ziel minimum(2,5,5)! • Andere in der Berechnung von Bi, i ≤ k, verbleibende Wahlmöglichkeiten werden aus dem Suchbaum eliminiert (Löschung nutzloser Zweige). Eine logisch korrekte Definition des minimum-Programms: minimum(X,Y,X) :- X≤Y, !. minimum(X,Y,X) :- X>Y, !. G. Görz, FAU, Inf.8 12–29 G. Görz, FAU, Inf.8 12–31 • Falls Backtracking tatsächlich den Cut erreicht, scheitert der Cut und die Suche wird fortgesetzt mit der letzten Auswahl, die getroffen wurde, bevor G das C wählte. Die “Closed World Assumption” und die Negation in PROLOG Cuts, die verwendet werden, um Determinismus auszudrücken — d.h., dass für jedes anwendbare Ziel nur eine der Klauseln erfolgreich verwendet werden kann, um es zu beweisen — heissen “grüne Cuts”. PROLOG benutzt die Closed Word Assumption (CWA). Mit cut und fail kann eine (eingeschränkte) Form der Negation definiert werden — nicht die logische Negation, weil deren Axiomatisierung nicht-HORN ist: ⇒ Einsparung von Zeit und Speicherplatz. not(P) :- call(P), !, fail. not(P). D.h.: Es wird ein Beweis von P erzwungen, auf den im Erfolgsfall eine Cut-Fail-Kombination folgt, die scheitert. Andernfalls ist die zweite Klausel erfolgreich. G. Görz, FAU, Inf.8 12–30 G. Görz, FAU, Inf.8 12–32 Zur Negation “Nicht-Vorkommen der Wahrheit einer Aussage” ist im allgemeinen nicht dasselbe wie die Wahrheit der negierten Aussage. Annahme, dass es verschiedene Wissensquellen für den Beweis und die Zurückweisung einer Behauptung gibt — Inkonsistenzen in grossen Datenbasen werden nicht ausgeschlossen, weil A+∧ A− kein Widerspruch (aber möglicherweise eine Warnung!) und A+∨ A− keine Tautologie ist. Beispiele: • Medizinische Diagnose • Rechtsprechung: Freispruch — Unschuld vs. Mangel an Beweisen • Telefonbuch: Nicht jeder, der einen Anschluss hat, ist aufgeführt. Verschiedene Deutungen der “Negation” im Unterschied zur klassischen Logik: G. Görz, FAU, Inf.8 12–33 • CWA: Eine Datenbasis D möge ein Modell U beschreiben. Wenn ein Fakt A nicht aus D folgt, wird ¬A als wahr angesehen. Gilt nur, wenn D das Modell U vollständig beschreibt. Verbleibende Probleme: Unentscheidbarkeit und nicht-monotone Schlüsse (s.u.). 12–35 Ist PROLOG nicht-monoton? Beachte: CWA and NAF. • NAF: ¬A wird als wahr angesehen, wenn alle Beweisversuche terminiert haben und A nicht aus D bewiesen werden konnte. Um ¬A anzunehmen, muss die Unbeweisbarkeit von A bekannt sein: die Negation von PROLOG. • Strikte CWA: ¬A ist wahr, wenn das Fakt A nicht in D enthalten ist. Beispiel: Personen, die nicht im Telefonbuch aufgeführt sind, haben keinen Anschluss. • Unabhängige Beschreibungen von “A” und “not A” durch zwei verschiedene Prädikate A+ and A−. Wird A+ bewiesen, so ist A wahr, wird A− bewiesen, so ist ¬A wahr. G. Görz, FAU, Inf.8 G. Görz, FAU, Inf.8 12–34 Beispiel: Ein Fahrplan enthalte die Abfahrtszeiten p(7). p(8). p(9). Die Anfrage :- p(8:30). resultiert in der Antwort “no”, was not(p(8:30)) entspricht. ⇒ Nicht-monotoner Schluss, denn, wenn p(8:30) zur KB hinzugefügt wird, folgt not(p(8:30)) nicht mehr, sondern stattdessen p(8:30)! Gegenargument: Die Logik von PROLOG ist äquivalent zu klassische Logik + CWA — trifft nicht zu, denn Angenommen, es gäbe eine weitere Regel, die besagt G. Görz, FAU, Inf.8 12–36 p(8:30) :- not(p(7:30)). Wenn wir klassische Logik + CWA annehmen, dann ist die Antwort auf die Anfrage :- p(8:30). “no”, weil p(8:30). nicht explizit angegeben ist. Aber PROLOG antwortet “yes” auf die Anfrage :- p(8:30)., weil p(7:30) scheitert! G. Görz, FAU, Inf.8 12–37 Verknüpfung logik-orientierter mit funktionaler Programmierung Einbettung von PROLOG in SCHEME?? • Funktionale Einbettung : Ein PROLOG-Interpreter wird in Scheme implementiert. Es kann vorgesehen werden, dass sich PROLOG und Scheme wechselseitig aktivieren. Beispiel: Query Language System in Abelson/Sussman, Kap. 4.4 Nichtdeterminismus wird mittels Strömen implementiert • Umgebungseinbettung : Referenzen von PROLOG-Identifikatoren beziehen sich auf Identifikatorbindungen in Scheme. Möglich, da Scheme Closures unterstützt. • Vollständige Einbettung : Kontrollkontext ist verfügbar und kann manipuliert werden. Möglich, da Scheme Continuations unterstützt (Haynes: “Logic Continuations”). Beispiel: SCHELOG (in SLIB) G. Görz, FAU, Inf.8 12–38