Prolog Florian Kleene

Transcrição

Prolog Florian Kleene
Westfälische Wilhelms-Universität Münster
Ausarbeitung
Prolog
im Rahmen des Seminars Programmiersprachen
Florian Kleene
Themensteller: Prof. Dr. Herbert Kuchen
Betreuer: Dipl.-Medienwiss. Susanne Gruttmann
Institut für Wirtschaftsinformatik
Praktische Informatik in der Wirtschaft
Inhaltsverzeichnis
1 Einführung in Prolog
1
1.1
Entstehung und Geschichte . . . . . . . . . . . . . . . . . . . . . . . .
1
1.2
Prolog-Systeme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.3
Anwendungsgebiete . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
2 Aufbau von Prolog-Programmen
3
2.1
Grundsätzliche Struktur . . . . . . . . . . . . . . . . . . . . . . . . .
3
2.2
Fakten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
2.3
Regeln . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
2.4
Anfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
2.5
Code-Beispiel: Stammbaum . . . . . . . . . . . . . . . . . . . . . . .
6
3 Funktionsweise des Interpreters
3.1
Grundlagen der Logik
8
. . . . . . . . . . . . . . . . . . . . . . . . . .
8
3.1.1
Aussagenlogik . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
3.1.2
Prädikatenlogik . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.2
Unifikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.3
Resolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.4
Backtracking und der Cut . . . . . . . . . . . . . . . . . . . . . . . . 15
4 Prolog in der Praxis
17
4.1
Expertensysteme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.2
Code-Beispiel: Send + More = Money . . . . . . . . . . . . . . . . . 19
5 Zusammenfassung und Fazit
20
A Anhang
22
A.1 Code-Beispiel Stammbaum . . . . . . . . . . . . . . . . . . . . . . . . 22
A.2 Wahrheitstabelle zur Resolutionsprüfung . . . . . . . . . . . . . . . . 23
A.3 Abarbeitungsreihenfolge von Anfragen an den Prolog-Interpreter (trace) 24
Literaturverzeichnis
25
i
Kapitel 1: Einführung in Prolog
1
1.1
Einführung in Prolog
Entstehung und Geschichte
Prolog ist die wohl bekannteste logische Programmiersprache. Entwickelt wurde sie
Anfang der 1970er Jahre vom französischen Forscher Alain Colmerauer und seinen
Mitarbeitern am Groupe d’Intelligence Artificielle in Marseille. Der Name Prolog
entstand aus dem französischen PROgrammation en LOGigue“, was mit Program”
”
mieren in Logik“ ins Deutsche übersetzt werden muss. Aufbauend auf den Ideen des
Forschers Edgar F. Codd zu relationalen Datenbankmodellen [Bo87, S. 8], J.A. Robinsons Arbeit zum Resolventenprinzip und dem Unifikationsverfahren von Jacques
Herbrand [CL90, S. 2] entwickelte Colmerauer zunächst System-Q. System-Q war
ein Frage-Antwort-System, welches auf Hornklauseln aufbaute und die oben genannten Prinzipien der Resolution und Unifikation zur Beweisführung ausnutzte [CL90,
S. 2]. Ausgehend von diesem System entstand mit Unterstützung von P. Roussel
und R. Pasero die Sprache Prolog.
Der erste Interpreter für Prolog wurde 1973 in Fortran geschrieben und um 1975
stand der erste Compiler zur Verfügung. Zu dieser Zeit wurde Prolog nur von einem
engen Personenkreis der Artificial-Intelligence-Forscher genutzt und geschätzt. Erst
als die japanische Regierung 1981 Prolog zur Basissprache ihrer Rechnersysteme
”
der 5. Generation“ – eine Rechnerarchitektur, die viele parallel arbeitende Prozessoren vorsieht – ernannte, erlangte Prolog einen größeren Bekanntheitsgrad. Zwar ist
die Bedeutung der Programmiersprache Prolog in der Folgezeit in den Hintergrund
gerückt und sicher keiner breiten Masse mehr bekannt, doch werden auch heute noch
praktische Anwendung in Prolog programmiert. Als Beispiele lassen sich Programme zur Fahrplangestaltung bei Zugverspätungen, zur Minimierung von Materialverbrauch oder zur Aufstellung von Schicht- und Stundenplänen anführen [IF08].
Im Gegensatz zu prozeduralen Programmiersprachen ist der Programmierer in Prolog lediglich aufgefordert das Problem zu beschreiben. Er muss jedoch keinen Lösungsalgorithmus spezifizieren. Insofern ist Prolog deklarativ wie beispielsweise die
bekannte Structured Query Language (SQL) für Datenbanken und es steht die Frage nach dem Was gelöst werden soll“ im Gegensatz zur Frage nach dem Wie es
”
”
gelöst werden soll“ bei imperativen oder objektorientierten Programmiersprachen
im Vordergrund. Dennoch bedient auch Prolog sich bei der Lösungssuche einiger
prozeduraler Elemente [KS88, S. 13], die im Kapitel 3 aufgezeigt werden.
1
Kapitel 1: Einführung in Prolog
1.2
Prolog-Systeme
Als die Programmiersprache Prolog nach der ersten Entwicklung durch A. Colmeraurer größere Bekanntheit erlangte, entwickelte sich eine Vielzahl von verschiedenen
Prolog-Systemen. Bekannte Namen sind in diesem Zusammenhang Arity-Prolog,
Micro-Prolog, Prolog II und III, Turbo-Prolog, SWI-Prolog, IF/Prolog und eine
Vielzahl anderer [Be88, S. 275]. Die Systeme unterschieden sich im Hinblick auf die
Anzahl der Schnittstellen zu anderen Programmiersprachen oder die dem Anwender
zur Verfügung gestellten Utilities (Interpreter, Compiler, Editor, Bugtracker, usw.).
Außerdem gibt es in den Systemen eine unterschiedliche Syntax und verschiedene
Bezeichnungen und Anzahlen für die sog. Built-In-Prädikate – einer Art Grundwortschatz bzw. Schlüsselwörter.
Im Laufe der Zeit bildeten sich zwei Standards für die Syntax heraus. Zum einen
war dies die Marseille-Syntax, wie sie ursprünglich von Alain Colmerauer aufgestellt
wurde, und zum anderen die Edinburgh-Syntax [Be88, S. 275 ff.]. Erst im Jahr 1995
wurde bei der ISO der Standard ISO/IEC 13211-1:1995 [ISO95] und im Jahr 2000
der zweite Teil ISO/IEC 13211-2:2000 [ISO00] aufbauend auf der Edinburgh-Syntax
festgelegt. Zumindest den ersten Teil des ISO-Standards aus dem Jahr 1995 implementieren heute die Systeme IF/Prolog und SWI-Prolog, die in größeren Kreisen
Verbreitung gefunden haben. SWI-Prolog wird in der Version 5.6.64 im Rahmen
dieser Arbeit verwendet.
1.3
Anwendungsgebiete
Zunächst ist zu sagen, dass es sich bei Prolog um eine universelle Programmiersprache handelt [CL90, S. 3], die also prinzipiell für diverse Gebiete in der Informatik
einsetzbar ist. Ursprünglich entwickelt wurde sie jedoch für die algorithmische Verarbeitung natürlicher Sprachen [KS89, S. 9] – also den Bereich der Computerlinguistik.
Aus diesem Ursprung heraus ergibt sich, dass Prolog insbesondere für die verschiedenen Teilgebiete der künstlichen Intelligenz, wie Spracherkennung und Bildverarbeitung und weniger für arithmetische Operationen geeignet ist. Neben dem Gebiet
der Computerlinguistik findet Prolog seine Anwendung in Expertensystemen, die im
Kapitel 4.1 dieser Arbeit näher erläutert werden, und in der Lehre und Forschung
[CL90, S. 3, 4].
2
Kapitel 2: Aufbau von Prolog-Programmen
2
Aufbau von Prolog-Programmen
2.1
Grundsätzliche Struktur
Ein Prolog-Programm besteht aus einer sog. Wissensbasis, die einen Ausschnitt aus
der Realwelt darstellt. In der Wissensbasis werden Fakten und Regeln, die die Eigenschaften der Objekte aus der Realwelt und deren Beziehungen widerspiegeln,
gespeichert. Fakten und Regeln werden durch den Programmierer mit Hilfe eines
Editors in einer Datei gespeichert, von manchen Systemen kompiliert (z. B. Arity Prolog [Be88, S. 277]) und anschließend vom Interpreter, der die Aufgabe eines
Theorembeweisers bzw. einer Inferenzmaschine übernimmt, geladen. Um Erkenntnisse aus der Wissensbasis zu erlangen, ist der Nutzer aufgefordert Anfragen an den
Interpreter abzugeben, die dieser versucht durch die Wissensbasis zu beweisen oder
zu widerlegen.
Auch in diesem Aspekt wird ein wesentlicher Unterschied zu den heute mehr gebräuchlichen Programmiersprachen deutlich und man erkennt die Ursprünge des
Frage-Antwort-Systems wieder. Der schematische Aufbau eines Prolog-Programms,
der an die Darstellung aus [KS89, S. 15] angelehnt ist, ist in der nachfolgenden
Grafik noch einmal zu erkennen.
Editor
Benutzerschnittstelle
(Anfragen)
Interpreter
(Inferenzmaschine)
Wissensbasis
(Fakten und Regeln)
Abbildung 1: Bestandteile der Programmiersprache Prolog
2.2
Fakten
Fakten in Prolog bezeichnen Aussagen über Objekte oder die Beziehung zwischen
Objekten, die immer als eindeutig wahr angesehen werden [KS88, S. 16]. Die generelle Struktur eines Fakts lässt in Anlehnung an die Backus-Naur-Form beschreiben
durch:
f akt ::= f unktor. | f unktor({argument, }∗0 argument).
3
Kapitel 2: Aufbau von Prolog-Programmen
Fakten bestehen also entweder aus einem Funktor oder aus einem Funktor auf den
in runden Klammern beliebig viele durch Kommata getrennte Argumente folgen
[KS88, S. 76]. Für alle nachfolgenden Quellcodebeispiele sei darauf hingewiesen,
dass Zeilenkommentare in Prolog durch %“ eingeleitet und Blockkomentare durch
”
/* ... */“ eingeschlossen werden. Fakten und Regeln werden am Ende der Zeile
”
durch einen Punkt abgeschlossen.
true . % Nullstelliger Fakt .
student ( philipp ). % Philipp ist ein Student .
vater ( reinhold , florian ). % Reinhold ist Florians Vater .
Zu beachten ist, dass Prolog kein tieferes Verständnis von Fakten gewinnt, sondern
lediglich Zeichenfolgen verarbeitet. Die Aussage Reinhold ist Florians Vater“ aus
”
dem dritten Fakt entsteht aus der Interpretation des Programmieres heraus und
könnte auch durch Florian ist Reinholds Vater“ festgelegt werden. Die Art und
”
Weise die Reihenfolge der Argumente zu lesen sollte daher einmalig vom Programmierer festgelegt werden [CM03, S. 4].
Für die Programmierung von Fakten gilt folgende Syntax [KS88, S. 18]:
1. Der Bezeichner – auch Funktor genannt – eines Fakts beginnt mit einem Kleinbuchstaben. Dadurch wird er vom Prolog-Interpreter als Konstante aufgefasst.
2. Auf den Funktor folgen direkt in Klammern die Argumente. Mehrere Argumente werden durch Kommata voneinander abgetrennt.
3. Die Argumente eines Fakts können selbst auch wieder Fakten sein. Fakten
oder verschachtelte Fakten werden als Struktur bezeichnet.
4. Die Anzahl der Argumente, die beliebig groß aber auch Null sein kann, wird
als Stelligkeit bezeichnet. Fakten mit gleichem Funktor und gleicher Stelligkeit
werden unter dem Begriff Prädikat zusammengefasst.
5. Alle Fakten werden mit einem Punkt abgeschlossen.
2.3
Regeln
Regeln ermöglichen es dem Prolog-Interpreter Wissen abzuleiten und vereinfachen
es dem Programmierer eine Vielzahl gleich gearteter Fakten in der Wissensbasis
darzustellen [KS88, S. 28]. Die allgemeine Struktur einer Regel ist gegeben durch:
regel ::= f akt : − {struktur, }∗1 struktur.
4
Kapitel 2: Aufbau von Prolog-Programmen
Angenommen jeder Student interessiere sich für Informatik. Dies ist mit unserer
bisherigen Kenntnis nur möglich, indem jeweils zwei Fakten pro Person in die Wissensbasis aufgenommen werden:
student ( florian ). % Florian ist Student .
% Florian interessiert sich für Informatik .
interesse ( florian , informatik ).
student ( philipp ). % Philipp ist Student .
% Philipp interessiert sich für Informatik .
interesse ( philipp , informatik ).
Effizienter ist dies durch eine einzige Regel in Prolog ausdrückbar: Jemand in”
teressiert sich für Informatik, falls er Student ist.“ Mit Hilfe von Regeln wird die
Wissensbasis übersichtlicher und bei vielen gleichartigen Fakten verkürzt sie sich
enorm.
student ( florian ). % Florian ist Student .
student ( philipp ). % Philipp ist Student .
% eine einzige Regel
interesse (X , informatik ) : - student ( X ).
Den linken Teil der Regel vor dem :-“ bezeichnet man als Kopf, den Teil auf der
”
rechten Seite als Rumpf der Regel. Regeln sind so zu lesen, dass der Kopf der Regel
als wahr angesehen werden kann, sofern alle Voraussetzungen im Rumpf erfüllt, d.h.
wahr sind. Das :-“ muss somit als umgedrehter Implikationspfeil gelesen werden.
”
Prinzipiell können auch Fakten in Form von Regeln dargestellt werden. Der Kopf
der Regel besteht dann aus dem Fakt selbst und der Rumpf aus dem null-stelligen
Prädikat true. Der Fakt mensch(florian). würde also zu der Regel mensch(florian
):- true. umgeformt.
Für die Programmierung von Regeln gilt folgende Syntax [KS88, S. 28]:
1. Der Kopf der Regel besteht aus genau einem Fakt, der als Argumente sowohl
Konstanten als auch Variablen, die in Prolog mit einem Großbuchstaben oder
einem Unterstrich begonnen werden, aufweisen kann.
2. Der Rumpf der Regel besteht aus einer oder mehreren Strukturen, die durch
Kommata oder Semikola voneinander abgetrennt werden. Das Komma in Prolog bezeichnet dabei das logische Und, während das Semikolon für das logische
Oder verwendet wird.
5
Kapitel 2: Aufbau von Prolog-Programmen
3. Der Geltungsbereich einer Variablen ist auf exakt eine Regel beschränkt, d.h.
Variablen mit derselben Bezeichnung in verschiedenen Regeln sind voneinander
unabhängig.
4. Jede Regel wird durch einen Punkt abgeschlossen.
Fakten und Regeln, die nach der obigen Syntax aufgebaut sind, werden in Prolog
als Klauseln – genauer als Programmklauseln – bezeichnet.
2.4
Anfragen
Die Benutzung von Prolog-Programmen geschieht dadurch, dass der Nutzer am
Prolog-Prompt, der durch ?-“ symbolisiert wird, Anfragen abgibt. Anfragen müssen
”
aus einer oder mehreren durch Kommata oder Semikola getrennten Strukturen, die
auch Variablen beinhalten können, bestehen. Der Geltungsbereich einer Variablen
ist in diesem Fall auf den Bereich einer einzelnen Anfrage beschränkt. Der Interpreter
versucht die Anfrage aus der Wissensbasis abzuleiten und antwortet mit true, false
oder, falls die Anfrage Variablen beinhaltete, mit einer Variablenbelegung, die bei
entsprechender Anfrage true liefern würde.
2.5
Code-Beispiel: Stammbaum
Im Folgenden soll der Umgang mit Fakten, Regeln und insbesondere Anfragen anhand eines Beispielprogramms gezeigt werden. Das Äquivalent zum Hello-World”
Programm“ in imperativen Programmiersprachen ist die Implementierung eines
Stammbaumes in logischer Programmierung. Der als Beispiel gewählte Stammbaum
ist in der folgenden Grafik zu sehen, wobei die ausgegrauten Personen nur zur optischen Vervollständigung des Stammbaumes eingezeichnet sind. Die zugehörige Wissensbasis, die nach oben beschriebener Syntax aufgebaut ist, befindet sich im Anhang
auf Seite 22 und soll als Code-Grundlage für die gesamte Seminararbeit dienen. Sie
enthält neben den offensichtlichen Fakten einige Regeln, die die Verwandtschaftsverhältnisse beschreiben.
6
Kapitel 2: Aufbau von Prolog-Programmen
Adam + Eva
Hermann + Katharina
Tina + Wilhelm
Reinhold + Doris
Florian
Thomas
Steffen
Abbildung 2: Darstellung des Staummbaumes
Zunächst werden einige Anfragen gestellt, die sich direkt auf Fakten in der Wissensbasis beziehen, also durch einfaches Vergleichen bewiesen oder widerlegt werden
können.
?-
mutter ( doris , thomas ).
true .
?-
vater ( hermann , thomas ).
false .
?-
mensch ( tobias ).
false .
Wie die letzte Anfrage zeigt, können Anfragen, die sich auf Aussagen beziehen, die
nicht in der Wissensbasis abgebildet sind, nicht bewiesen werden. Die Wissensbasis
repräsentiert eine abgeschlossene Welt in der alles, was nicht explizit bewiesen werden kann, als falsch angesehen wird. Die Anfrage wird daher vom Interpreter mit
false beantwortet. Für die nachfolgenden Anfragen ist jeweils die Auswertung einer
oder mehrerer Regeln nötig. Die Funktionsweise des Interpreters für die Schlussfolgerungen wird in den kommenden Kapitel ausführlich vorgestellt.
?-
elternteil ( doris , florian ) . % Beispiel 1
true .
?-
vorfahre (X , reinhold ) . % Beispiel 2
X = hermann ;
X = katharina ;
false .
?-
vorfahre ( doris , Y ) . % Beispiel 3
Y = florian ;
Y = thomas ;
false .
7
Kapitel 3: Funktionsweise des Interpreters
Neben Anfragen, die true oder false als Ergebnis zurück liefern (Beispiel 1: ?elternteil(doris,florian).), können auch Anfragen abgeben werden, die Varia-
blen beinhalten (Beispiele 2 und 3). Derart gestaltete Anfragen beantwortet der
Interpreter mit Variablenbelegungen, die zum Ergebnis true führen würden. Gibt es
mehrere Lösungen, so ist der Nutzer aufgefordert durch Eingabe eines Semikolons
eine weitere Lösung zu verlangen. Der Interpreter gibt solange Lösungen zurück, bis
es keine weiteren mehr gibt und endet dann mit false.
Das dritte Beispiel soll nochmals verdeutlichen, dass der Prolog-Interpreter sowohl
die Anfragen als auch die Wissensbasis lediglich als Zeichenfolgen verarbeitet. Das
Prädikat vorfahre( , ) ist daher auch dazu geeignet Nachfahren zu bestimmen.
3
3.1
3.1.1
Funktionsweise des Interpreters
Grundlagen der Logik
Aussagenlogik
Um die Funktionsweise des Prolog-Interpreters verstehen zu können, erscheint es
zunächst sinnvoll, die Grundlagen der Logik, die das Fundament der Programmiersprache bilden, darzustellen. Die Syntax von Prolog ist nämlich nicht willkürlich
gewählt, sondern lehnt sich stark der Prädikatenlogik erster Ordnung an. Zunächst
sei jedoch die Aussagenlogik als Ausgangspunkt für die Prädikatenlogik vorgestellt.
Einfache aussagenlogische Formeln bestehen aus durch Und (∧) oder Oder (∨) verknüpften Aussagen (negierte (¬) oder nicht-negierte Literale), wobei ein Wahrheitswert für eine Formel aus den Wahrheitswerten der Literale resultiert [Sch00, S. 15].
Die Formel a ∧ (¬b ∨ c) ∧ b ist beispielsweise für die Belegung a = 1, b = 1, c = 1
erfüllt, d. h. =1. Die Formel (a ∧ b) ∧ (¬a ∧ b) ist hingegen für keine Belegung erfüllt.
Man nennt eine solche Formel Kontradiktion, während Formeln, die für alle Belegungen erfüllt sind, Tautologien genannt werden.
Prolog arbeitet nicht mit aller Art aussagenlogischer Formeln, die erzeugbar sind. Es
hat sich herausgestellt, dass sich Hornformeln – benannt nach dem amerikanischen
Logiker Alfred Horn – in Kombination mit der SLD-Resolutionsregel (Linear resolution with S elected function for Definite clauses) gut maschinell verarbeiten lassen
und gleichzeitig auch viele Praxisprobleme in dieser Form abbildbar sind [KS88,
S. 36]. Die sog. Hornformeln, deren Aufbau im Folgenden gezeigt werden soll, stellen eine Teilmenge aller aussagenlogischen Formeln dar:
8
Kapitel 3: Funktionsweise des Interpreters
• Hornklausel: Eine Hornklausel ist eine Disjunktion (Oder-Verkünpfung) von
Literalen, wobei maximal ein Literal in nicht-negierter Form aufritt.
Beispiele: a; (¬a); (¬a ∨ b); (¬a ∨ ¬b ∨ c); (¬a ∨ ¬b ∨ ¬c);
• Hornformel: Eine Hornformel ist eine Konjunktion (Und-Verknüpfung) von
Hornklauseln.
Beispiele: a; (¬a) ∧ (¬a ∨ b); a ∧ (¬a ∨ ¬b ∨ c) ∧ (¬a ∨ ¬b ∨ ¬c);
Eine Hornformel ist also eine Formel in konjunktiver Normalform, d. h. eine Konjunktion von Disjunktionstermen, bei der jeder Disjunktionsterm höchstens ein nichtnegiertes Literal aufweist [Sch00, S. 26, 31].
Den Fakten, Regeln und Anfragen in Prolog-Programmen lassen sich charakteristisch drei verschiedene Arten der Hornformeln zuordnen:
Ein Fakt ist eine Hornformel, die aus exakt einem nicht-negierten Literal besteht.
Eine Regel enthält ein oder mehrere negierte Literale und exakt ein positives Literal und eine Anfrage besteht nur aus negierten Literalen. Um dies ersichtlich zu
machen muss zunächst die Auflösung des umgedrehten Implikationspfeils innerhalb
der Anfragen und Regeln vorgenommen werden. Es gilt (a ← b) = (a ∨ ¬b) und
allgemeiner unter Ausnutzung der De Morgan’schen Regel a ← (b1 ∧ ... ∧ bn ) =
a ∨ ¬(b1 ∧ ... ∧ bn ) = a ∨ ¬b1 ∨ ... ∨ ¬bn [Sch00, S. 14, 24]. Wendet man diese Regeln
entsprechend an, so lässt sich folgende Tabelle zusammenstellen:
Darstellung in Prolog
Codierung durch
Auflösung des
Symbole
Implikationspfeils
Fakt
student(florian).
a
a
Regel
interesse(florian,informatik)
c ← a, b, ...
c ∨ ¬(a ∧ b ∧ ...)
= c ∨ ¬a ∨ ¬b ∨ ¬...
:- student(florian), ...
Anfrage
?- interesse(florian,informatik).
←b
¬b
Tabelle 1: Charakteristika von Fakten, Regeln und Anfragen in Hornklauseln
Fakten und Regeln bezeichnet man, da sie jeweils ein nicht-negiertes Literal enthalten, als Programmklauseln. Anfragen hingegen werden als Zielklauseln bezeichnet.
Um eine Zielklausel beweisen zu können, muss diese unter Ausnutzung der Programmklauseln soweit äquivalent transformiert werden, dass der Beweis aus der Wissensbasis ersichtlich wird. Dabei kommt dem Schlussfolgern aus der Logik die entscheidende Bedeutung zu. Eine Formel lässt sich aus den Ausgangsformeln schlussfolgern, wenn die neue Formel für alle Belegungen, für die die Ausgangsformeln wahr
liefern, ebenfalls wahr liefert [KS88, S. 39].
9
Kapitel 3: Funktionsweise des Interpreters
Beispiel: Aus (a ∨ b) ∧ (¬b ∨ c) lässt sich die Formel (a ∨ c) folgern, da
nicht gleichzeitig b und ¬b wahr sein können. Das b kann also eliminiert
werden. Nachvollziehbar wird die Eliminierung sofort, nachdem man die
Ausgangsformel zu (¬a → b) ∧ (b → c) und das Ergebnis zu (¬a → c)
umgeformt hat.
Wendet man diese Regel der Eliminierung auf eine Kontradiktion wie z. B.
(¬a∧b)∧(a∧¬b) an, so bleiben keine Literale übrig und es entsteht die leere Klausel
(t). Diese Erkenntnis und das Wissen darüber, dass eine Formel genau dann unerfüllbar (widerspruchsvoll) ist, wenn ihre Negation eine Tautologie ist, führt zum
Unerfüllbarkeitstest. Fügt man das negierte Literal aus der Anfrage dem Programm
hinzu und gelingt es, die leere Klausel herzuleiten, so gibt es einen Widerspruch
[Sch00, S. 37 ff.]. Dies ist äquivalent dazu, dass die unnegierte Anfrage sich aus dem
Programm ableiten lässt, also beweisbar ist.
Beispielsweise existiere eine Wissensbasis {e, c, (d ← e), (b ← c, d), (a ← b)} und
es werde die Anfrage nach ← a gestellt, so muss für den Beweis der Zielklausel in
Kombination mit dem Programm die leere Klausel erzeugt werden können. Gelingt
dies, so ist a beweisbar. In der nachfolgenden Darstellung ist in jeder Zeile ein Eliminierungsschritt (Resolution) ausgeführt worden. Ziel- und Programmklausel sind
innerhalb einer Zeile durch Komma voneinander abgetrennt und passen“ deswegen
”
zu einander, weil die Zielklausel nur negierte Literale und Fakten und Köpfe von
Regeln stets positive Literale sind (vgl. auch obige Tabelle):
(← a), (a ← b)
(← b), (b ← c, d)
(← c, d), c
(← d), (d ← e)
(← e), e
t
Die Anfrage ← a ist also aus dem Programm beweisbar. Die zugehörige, vollständige
Wahrheitstabelle findet der interessierte Leser im Anhang auf Seite 23.
3.1.2
Prädikatenlogik
Für die vollständige Betrachtung von Prolog-Programmen genügt die Aussagenlogik
alleine jedoch noch nicht, da keine Funktoren und keine Variablen, wie sie in PrologProgrammen enthalten sind, nachgebildet werden können. Die Prädikatenlogik erweitert die Aussagenlogik um Quantoren, Funktions- und Prädikatssymbole [Sch00,
S. 50]. Insbesondere die Quantoren ∃ (es existiert ein) und ∀ (für alle) sind in diesem
10
Kapitel 3: Funktionsweise des Interpreters
Zusammenhang unabdingbar, da z. B. der Aussage vater(X, f lorian) kein Wahrheitswert zugeordnet werden kann, solange die Variable X nicht durch einen Quantor
festgelegt ist. Ist X durch einen Quantor festgelegt, d. h. gebunden, so lässt sich ein
Wahrheitswert für ∃X : vater(X, f lorian) oder ∀Y : mutter(Y, f lorian) in Bezug
auf die Wissensbasis bestimmen.
In Prolog sind Variablen in Programmklauseln implizit allquantifiziert, da sie für
einen Beweis nur einmalig festgelegt werden können. Anfragen hingegen sind implizit existenzquantifiziert, weil es genügt eine Variablenbelegung aufzufinden, die die
Anfrage beweist.
Um die Beweisbarkeit einer Anfrage überprüfen zu können, muss diese daher zunächst
durch Transformationen in eine Form überführt werden, die keine Existenzquantoren mehr enthält. Durch den Vorgang der Skolemisierung, benannt nach dem norwegischen Mathematiker Thoralf Skolem, kann dies bewerkstelligt werden [Sch00,
S. 63 f.]. Grundlage dieses Verfahrens ist, dass existenzquantifizierte Variablen durch
eine Skolemkonstante bzw. bei voranstehendem Allquantor durch eine Skolemfunktion ersetzt werden können ohne dass sich der Wahrheitswert ändert [Sch00, S. 64, 65].
∀Y : ∃X : mann(Y ) → lieben(Y, X) ⇔ ∀Y : mann(Y ) → lieben(Y, fs (Y ))
Die Aussage Für alle Männer Y existiert eine Frau X, so dass Y X liebt“ wird
”
durch den Vorgang der Skolemisierung ersetzt durch Für alle Männer Y gibt es eine
”
vom konkreten Mann Y abhängige Frau X, die Y liebt“. Die existenzquantifizierte
Variable X wird also durch die Skolemfunktion fs (Y ) substituiert.
Nachdem alle existenzquantifizierenden Variablen ersetzt worden sind, können die
Allquantoren ohne weitere Beachtung weggelassen werden, da Variablen in Aussagen
– wie bereits oben erwähnt – implizit allquantifizierend sind [KS88, S. 65]. Die
Beweisbarkeit kann jetzt mit Hilfe des gewöhnlichen Unerfüllbarkeitstests, der aus
dem vorigen Kapitel bekannt ist, hergeleitet werden.
Im folgenden Kapitel wird die Instanziierung von Variablen und der Beweisprozess in
Prolog vorgestellt. Das Themengebiet der reinen Logik wird verlassen und der Focus
auf das Verständnis der konkreten Arbeitsweise des Prolog-Interpreters gelegt.
3.2
Unifikation
Die Wortbedeutung Unifikation leitet sich aus den lateinischen Wörtern unus (eins)
und facere (machen) ab, so dass sich als Gesamtbedeutung zu eins machen“ oder
”
vereinigen“ ergibt [KS89, S. 29]. Ziel ist es mit Hilfe der Unifikation die an den
”
Interpreter gestellten Anfragen aus der Wissensbasis abzuleiten. Um eine Anfrage
11
Kapitel 3: Funktionsweise des Interpreters
beantworten zu können, durchsucht der Interpreter die Wissensbasis nach einem
Prädikat mit gleichem Funktor und gleicher Stelligkeit. Dieses Prädikat kann sowohl
der Kopf einer Regel als auch ein Fakt sein. Damit die Anfrage bewiesen werden
kann, müssen neben Prädikat und Stelligkeit zusätzlich auch die Argumente des
Prädikats unifizieren [KS88, S. 103]. Für die weitere Betrachtung wird aus Gründen
der Übersichtlichkeit zwischen den verschiedenen Arten der Argumente unterschieden. Unifizierbarkeit lässt sich mit Hilfe des internen, zweistelligen Prolog-Prädikats
=( , )“ am Prompt überprüfen.
”
1. Zwei Konstanten sind unifizierbar, falls ihre Zeichenketten übereinstimmen:
Die Anfrage ?- =(florian,florian). würde also unifizieren, d. h. mit true
beantwortet.
2. Eine (ungebundene) Variable und eine Konstante sind stets dadurch unifizierbar, dass die Konstante an die Variable gebunden wird. Man nennt diesen
Vorgang Instanziierung der Variablen:
Die Anfrage ?- =(X,florian). würde also dadurch unifizieren, dass an die
Variable X die Konstante florian gebunden würde.
3. Eine (ungebundene) Variable und eine Struktur sind stets dadurch unifizierbar,
dass die Struktur an die Variable gebunden wird:
Die Anfrage ?- =(mensch(florian),X). würde also dadurch unifizieren, dass
an die Variable X die Struktur mensch(florian) gebunden würde.
4. Zwei (ungebundene) Variablen sind stets dadurch unifizierbar, dass sie im Anschluss für den gleichen Wert stehen.
5. Zwei Strukturen sind dann unfizierbar, wenn sie den gleichen Funktor, die
gleiche Stelligkeit haben und jedes Argument auch nach den hier vorgestellten
Regeln unfizierbar ist:
?- =(kind(eltern(X,doris),florian),kind(eltern(reinhold,doris),florian
)). als Anfrage würde also dadurch unifizieren, dass an die Variable X die
Konstante reinhold gebunden würde, da der Funktor kind übereinstimmt, die
Stelligkeit jeweils zwei ist und auch die Argumente nach den Regeln 5, 2 und
1 unifizierbar sind.
Bei der Unifikation wird von den meisten Prolog-Interpretern – so auch von SWIProlog – auf den sog. Occurcheck aus Gründen der Effizienz verzichtet [KS89, S. 176].
Der Occurcheck stellt einen Kontrollmechanismus bereit, der überprüft, ob eine Variable in beiden zu unifizierenden Argumenten auftritt. Das einfachste Beispiel hierzu ist die Anfrage ?- =(X,f(X))., die prinzipiell vom Interpreter abgefangen werden
12
Kapitel 3: Funktionsweise des Interpreters
müsste, um eine unendliche Schleife zu verhindern.
Durch die Unifikation lässt sich die Arbeitsweise des Interpreters für die Anfrage
nach Fakten in der Wissensbasis erklären. Falls jedoch die Auswertung von Regeln
für die Beantwortung einer Anfrage hinzugezogen werden muss, so ist ein weiteres
Konzept – nämlich das der Resolution – nötig.
3.3
Resolution
Die Resolution bezeichnet einen Schlussfolgerungsmechanismus [CM03, S. 248], der
bereits im Kapitel zur Aussagenlogik kurz behandelt wurde und dazu verwendet
wird, logische Formeln auf Gültigkeit zu prüfen. Ergebnis der Resolution zweier
Klauseln ist eine neue dritte Klausel, die sich als Konsequenz aus den beiden gegebenen Klauseln mit Hilfe der Unifikation ergibt. Die Anfrage am Prompt stellt
die zu beweisende Klausel dar. In Kombination mit einer Regel (Resolution) ändert
sich die zu beweisende Klausel, so dass ein äquivalentes Problem entsteht, welches
im nächsten Schritt zu beweisen ist.
Nachfolgend ist der für die Anfrage ?- vorfahre(reinhold,thomas). relevante Ausschnitt aus dem Code-Beispiel Stammbaum wiedergegeben:
vater ( reinhold , thomas ) .
elternteil (X , Y ) : - vater (X , Y ) .
vorfahre (X , Y ) : - elternteil (X , Y ) .
Der Prolog-Interpreter ist aufgefordert die Anfrage ?- vorfahre(reinhold,thomas).
zu beweisen. Er durchsucht die Wissensbasis nach einem Prädikat mit dem Funktor
vorfahre und Stelligkeit 2. In der dritten Zeile des Code-Ausschnitts wird er fündig.
Die Unifikation bewirkt die Instanziierung der Variablen X=reinhold und Y=thomas.
Durch die Resolution verlagert sich das zu beweisende Problem von ?- vorfahre(
reinhold,thomas). zu ?- elternteil(reinhold,thomas)., wobei die instanziierten
Variablen bereits eingesetzt wurden.
In einem nächsten Schritt unifiziert ?- elternteil(reinhold,thomas). mit elternteil
(X,Y):- vater(X,Y).. Wieder werden X und Y instanziiert und als Ergebnis der
Resolution ergibt sich das neu zu beweisende Ziel ?- vater(reinhold,thomas)..
Die Anfrage ?- vater(reinhold,thomas). unifiziert mit dem Fakt vater(reinhold
,thomas). in der Wissensbasis. Die Anfrage ist folglich bewiesen, also wahr. Weil
durch die Unifikation und Resolution nur erfüllbarkeitsäquivalente Umformungen
ausgeführt wurden, ist daher auch die Anfrage ?- vorfahre(reinhold,thomas). mit
wahr zu beantworten. Dieses Ergebnis ergibt sich auch aus dem Schaubild des
13
Kapitel 3: Funktionsweise des Interpreters
Stammbaums.
Zum Abschluss dieses Kapitels soll noch auf die prozedurale Arbeitsweise des PrologInterpreters, die Prolog als Programmiersprache von der reinen Logik differenziert
[Be86, S. 101], eingegangen werden. Das prozedurale Vorgehen bei der Beweissuche
sollte dem Programmierer bei der Zusammenstellung der Wissensbasis immer bewusst sein, da es sonst leicht zu ungewollten Fehlern und Problemen kommen kann.
Prolog durchsucht bei Anfragen die Wissensbasis nach passenden, d. h. unifizierbaren Prädikaten, von oben nach unten. Besteht die Anfrage aus mehreren verknüpften
Strukturen, so wird versucht, diese in der Reihenfolge von links nach rechts zu beweisen. Ein einfaches Beispiel, das die Wichtigkeit der Reihenfolge in der Wissensbasis
untermauern soll, ist nachfolgend wiedergegeben (vgl. [KS88, S. 71]:
beweisbar ( X ) : - zirkel ( X ) .
zirkel ( Y ) : - beweisbar ( Y ) .
beweisbar ( egal ) .
Stellt man die Anfrage ?- beweisbar(egal)., so liefert obiges Programm niemals
das Ergebnis true, sondern der Interpreter gerät in eine unendliche Schleife, obwohl
die Anfrage als Fakt in der Wissensbasis vorliegt. Die Begründung liegt in der oben
genannten Suchreihenfolge des Interpreters und dem ungünstigen Aufbau der Wissensbasis, so dass der Interpreter nie die dritte Zeile des Codes erreicht. Aus der
formalen Logik heraus ist ein solches Verhalten natürlich nicht erwünscht. Die Reihenfolge der Fakten und Regeln sollte keine Rolle spielen [Be86, S. 101].
Insbesondere für rekursiv definierte Prädikate, die im Übrigen die einzige Möglichkeit
darstellen in Prolog iterative Schleifen wie z. B. die for-Schleife nachzubilden, ist es
notwendig die Abbruchbedingung der Rekursion stets vor dem rekursiv definierten Prädikat selbst in die Wissensbasis aufzunehmen. Als Beispiel hierfür sei das
Prädikat vorfahre(_,_). aus dem Code-Beispiel genannt:
/* Abbruchbedingung */
vorfahre (X , Y ) : - elternteil (X , Y ) .
/* rekursive F un k t io n s de f i ni t i on von vofahre (_ , _ ) .
Nur so sind beliebig weit entfernte Vorfahren
ermittelbar */
vorfahre (X , Y ) : - elternteil (Z , Y ) , vorfahre (X , Z ) .
Steht das rekursiv definierte Prädikat in der Wissensbasis vor der zugehörigen Abbruchbedingung, so ist das Prädikat wertlos, da es den Interpreter in eine Schleife
ohne Abbruch zwingt (vgl. oben).
14
Kapitel 3: Funktionsweise des Interpreters
3.4
Backtracking und der Cut
Die bisherigen Ausführungen erklären bereits einen großen Teil der Vorgehensweise
des Prolog-Interpreters. Jedoch ist bislang nicht geklärt worden, wie vorgegangen
wird, wenn der Prolog-Interpreter durch die Resolution in eine Sackgasse“ gerät.
”
Als Beispiel soll die Anfrage ?- elternteil(doris,florian). dienen. Der relevante
Code-Ausschnitt ist nachfolgend wiedergegeben:
mutter ( doris , florian ) .
elternteil (X , Y ) : - vater (X , Y ) .
elternteil (X , Y ) : - mutter (X , Y ) .
Wie im Kapitel zur Resolution beschrieben durchsucht der Prolog-Interpreter die
Wissensbasis von oben nach unten nach unifizierbaren Prädikaten. In diesem Fall
würde die Anfrage also mit der in Zeile 2 gezeigten Regel unifizieren. Nach Instanziierung der Variablen und Resolution verbleibt als neues Ziel der Beweis von
?- vater(doris,florian).. Diese Klausel kann in der Wissensbasis nicht aufgefun-
den werden, so dass man nach bisheriger Kenntnis davon auszugehen hat, dass der
Prolog-Interpreter mit false antworten würde.
Dies ist jedoch nicht der Fall. Der Prolog-Interpreter erkennt, dass er in eine Sack”
gasse“ geraten ist und geht einen Schritt in seiner Auswertungsreihenfolge zurück
(Backtracking) [KS88, S. 104]. Er überspringt also die Regel in Zeile 2 und wendet
stattdessen die Regel in Zeile 3 an, die sich ebenfalls mit der Anfrage unifizieren
lässt. Als neues Ziel verbleibt zu zeigen, dass ?- mutter(doris,florian). gilt. Da
dies ein Fakt der Wissensbasis ist, gibt der Prolog-Interpreter demzufolge true aus.
Die Reihenfolge der Abarbeitungen lässt sich in Prolog durch das nullstellige BuiltIn-Prädikat trace nachvollziehen. Zum besseren Verständnis der Abarbeitungsreihenfolge kann der trace in einem Und-/Oder-Suchbaum dargestellt werden [Be86,
S. 112]. Die Wurzel dieses Baumes bildet die Anfrage an den Interpreter. Ausgehend
von dieser Wurzel bestimmen sich die Nachfolger dann jeweils als alle möglichen Fakten oder Rümpfe von Regeln, die mit der Wurzel unifizieren. Die einzelnen Verzweigungen werden, da verschiedene Fakten und Regeln als voneinander unabhängiges
Wissen gesehen werden müssen, mit oder verknüpft werden. Hat eine Regel mehr
als eine Voraussetzung im Rumpf, so werden diese im Baum mit und verknüpft. Die
Blätter des Baumes stellen Fakten aus der Wissensbasis dar.
Die Beweissuche einer Anfrage geschieht durch Traversierung des Baumes. Um eine
Anfrage zu beweisen, müssen dann alle Nachfolger eines Und-Knotens und einer der
15
Kapitel 3: Funktionsweise des Interpreters
Nachfolger eines Oder-Knotens erfolgreich abgearbeitet werden. Scheitert der Beweis eines Teilziels, so wird zum letzten Oder-Knoten (Choicepoint), der noch nicht
bearbeitete Nachfolger aufweist, zurückgegangen (Backtracking) [Be86, S. 115]. Bei
einem Backtracking-Schritt werden Variableninstanziierungen, die bis zum Choicepoint vorgenommen wurden, rückgängig gemacht.
Der zur Anfrage ?- vorfahre(hermann,florian). gehörende Suchbaum ergibt sich
aus dem trace (vgl. Anhang, Seite 24). In den Knoten des Baumes lassen sich die
jeweils noch zu beweisenden Anfragen erkennen, angewandte Regeln sind durch die
Ziffern an den Kanten dargestellt und die gestrichelte Linie zeigt die Abarbeitungsreihenfolge.
vorfahre(hermann,florian)
X=hermann
Y=florian
X=hermann
Y=florian
ODER
4
3
elternteil(hermann,florian)
UND
ODER
1
vater(hermann,florian)
Z=reinhold
2
mutter(hermann,florian)
elternteil(Z,florian)
ODER
Z=reinhold
Legende zu den Regelnummern:
1: elternteil(X,Y) :- vater(X,Y).
2: elternteil(X,Y) :- mutter(X,Y).
3: vorfahre(X,Y) :- elternteil(X,Y).
4: vorfahre(X,Y) :- elternteil(Z,Y),vorfahre(X,Z).
Legende zu den Symbolen:
fail: Backtracking Schritt
exit: Teilziel erreicht
2
1
vater(reinhold,florian)
vorfahre(hermann,reinhold)
Z=doris
mutter(doris,florian)
3
elternteil(hermann,reinhold)
ODER
1
vater(reinhold,florian)
2
mutter(doris,florian)
Abbildung 3: Abarbeitung einer Anfrage dargestellt in einem Suchbaum
Der Suchbaum zeigt, dass die Abarbeitungsreihenfolge der Regeln von oben nach
unten und von links nach rechts einer Tiefensuche entspricht. Diese wird in Prolog in
Kombination mit Backtracking verwendet. Die Anfrage ist beweisbar, da im rechten
Teilbaum beide durch Und-verknüpfte Teilziele parallel erreicht werden können.
Der sogenannte Cut – ein nullstelliges Built-In-Prädikat mit dem Funktor ! – stellt
dem Programmierer ein Werkzeug zur Seite, das es ihm ermöglicht die Abarbeitungsreihenfolge des Interpreters dadurch zu steuern, dass Backtracking gezielt verhindert
wird [KS88, S. 120].
Der Programmierer beschränkt den Suchraum des Interpreters durch gezieltes Ab”
schneiden“ irrelevanter Teilbäume und kann somit die Effizienz von Programmen
steigern [Sch00, S. 152]. Eine andere Einsatzform von Cut erlaubt es dem Programmierer, nur exakt eine Lösung zu einem Problem ausgeben zu lassen und danach die
16
Kapitel 4: Prolog in der Praxis
Suche abzubrechen. Letztendlich kann mit Hilfe des Cut sogar das aus prozeduralen
Programmiersprachen bekannte if-then-else nachgebildet werden [Sch00, S. 152].
Aufgrund der Eigenschaften des Cut, dass er die Lösungssuche beeinflusst, wird er
in der Literatur kontrovers diskutiert. Auf der einen Seite ist es mit seiner Hilfe
möglich, die Effizienz der Auswertung zu steigern [Sch00, S. 152]. Auf der anderen
Seite wird er als Alptraum jedes Logikers“ [KS89, S. 142] bezeichnet, da er den
”
Prinzipien der logischen Programmierung Was statt Wie“ genau entgegenwirkt.
”
An dieser Stelle wird auf die genauere Darstellung der verschiedenen Möglichkeiten
des Cut verzichtet, da es sich nicht um eine für Prolog wesentliche Komponente
handelt. Es sei hierzu jedoch auf [Be86, S. 103ff.] und [KS88, S. 120 ff.] verwiesen.
4
4.1
Prolog in der Praxis
Expertensysteme
Nachdem die wesentlichen Aspekte der Programmiersprache Prolog vorgestellt wurden, kann jetzt auf die praktische Anwendung in Expertensystemen eingegangen
werden. Expertensysteme, die auch als wissensbasierte Systeme bezeichnet werden
[KS88, S. 240], sollen in einem gewissen Rahmen den menschlichen Experten ersetzen können. Dies ist immer dann nötig, wenn es nur eine sehr geringe Anzahl an
Experten in dem entsprechenden Fachgebiet gibt, die Komplexität der zu beachtenden Vorschriften besonders hoch ist (Beispiel: Behörden) oder das Spezialwissen
nur sehr selten benötigt wird (Behandlung von Ausfallsituationen) [Sa89, S. 24 f.].
Aus diesen Umständen ergibt sich, dass ein Expertensystem ähnliche Fähigkeiten
aufweisen muss, die auch ein menschlicher Experte besitzt. Es ist also zunächst eine genauere Analyse des menschlichen Experten von Nöten, bevor anschließend die
einzelnen Fähigkeiten in Bezug zu Prolog gesetzt werden können:
Als Experte wird i. A. eine Person bezeichnet, die umfangreiches Wissen
in einem bestimmten Fachgebiet besitzt und dieses Wissen kompetent
anwenden und auch erläutern kann. Das Wissen wurde durch Talent,
Übung und/oder langjährige Erfahrung gesammelt, wobei sich der Experte auch schnell neues Wissen aus externen Quellen aneignen kann. In
Problemsituationen steht der Experte in direkter Interaktion mit anderen Menschen. Er erfragt dabei problemrelevante Aspekte, um schließlich
das Problem lösen zu können (vgl. [KS88, S. 240], [Sa89]).
17
Kapitel 4: Prolog in der Praxis
Fasst man diese Fähigkeiten in einer schematischen Darstellung (vgl. [Be86, S. 26])zusammen, so ergeben sich verschiedene Komponenten, die ein Expertensystem aufweisen muss, um den Anforderungen nach obiger Definition zu genügen:
Benutzer
Expertensystem
Dialogkomponente
(Benutzerschnittstelle)
Wissensveränderungskomponente
Erklärungskomponente
Problemlösung
(Inferenzmechanismus)
Wissensbasis
(internes, externes, erfragtes Wissen)
Abbildung 4: Allgemeine Struktur eines Expertensystems
In Prolog kann durch das Konzept der Fakten und Regeln ein regelbasiertes Expertensystem aufgebaut werden. Die wichtigste Komponente dieses Systems stellt der
Inferenzmechanismus dar, da er die verschiedenen anderen Komponenten integrieren
und steuern muss. In Prolog wird diese Aufgabe durch den Interpreter übernommen,
so dass sich die Arbeitsweise als Tiefensuche in Kombination mit Backtracking charakterisieren lässt [CL90, S. 170].
Eng verknüpft mit dem Inferenzmechanismus ist die Repräsentation der verschiedenen Arten des Wissens – in Prolog Fakten und Regeln. Wichtig ist es, das erfragte
Wissen, welches erst im Rahmen der Interaktion mit dem Benutzer erlangt wird und
sich somit fall-spezifisch unterscheidet, von den zwei anderen Wissensarten zu abzugrenzen. Um erfragtes Wissen speichern zu können, unterstützt Prolog in diesem
Zusammenhang das dynamische Hinzufügen und Löschen von Fakten und Regeln
in die Wissensbasis zur Laufzeit. Dies wird durch die Built-In-Prädikate asserta( ).
und retract( ). und einige Abwandlungen von diesen realisiert [KS88, S. 179]. Externes Wissen erlangt der Prolog-Interpreter aus anderen Programmen, die über
Schnittstellen angebunden sind. Die Schnittstellen sind, wie in der Einleitung dargelegt, jedoch zwischen den verschiedenen Prolog-Systemen sehr inhomogen und
lassen sich nur für den Einzelfall detaillierter beschreiben.
Die Benutzerschnittstelle sollte nach Auffassung von Kleine Büning und Schmittgen
nicht in Prolog selbst realisiert werden [KS88, S. 245]. Dies erscheint auch logisch,
da Prolog sich nur sehr bedingt dazu eignet grafische Elemente einzubinden, sodass
lediglich eine Interaktion mit dem Benutzer am Prompt verbliebe. Der heutige Nutzer ist hingegen grafische Oberflächen gewöhnt und würde eine solche Interaktion
ablehnen. Die Erklärungskomponente muss dem Benutzer über die Benutzerschnitt18
Kapitel 4: Prolog in der Praxis
stelle auf verständliche Art und Weise den Problemlösungsprozess deutlich machen
können, da das Expertensystem ansonsten nur geringe Akzeptanz finden würde.
Aus der allgemein gehaltenen Beschreibung der verschiedenen Komponenten und
der Realisierung geht hervor, dass Benutzerschnittstelle, Inferenzmechanismus und
die Repräsentation des Wissens unabhängig von der konkreten Problemstellung implementiert werden können. Die Architektur sieht eine strikte Trennung von Wissen
und Wissensverarbeitung vor. Da die problemspezifische Wissensbasis in solch ein
System eingepflegt werden muss, spricht man daher auch von leeren Schalen oder
Shells [KS88, S. 243].
Das Produkt TWAICE der Firma Nixdorf ist eine solche Expertensystem-Shell,
die auf Prolog aufsetzt. Der interessierte Leser findet eine genauere Beschreibung
in [Sa89, S. 135-159]. In [KS88, S. 245-274] findet sich die ausführlich erläuterte,
vollständige Implementierung eines Expertensystems anhand eines Autokauf-Beispiels.
4.2
Code-Beispiel: Send + More = Money
Nachfolgend ist ein Beispielprogramm zur Lösung der Gleichung SEND + MORE =
MONEY wiedergegeben, um einen Vergleich von Prolog mit anderen Programmier-
sprachen zu ermöglichen. Jeder Buchstabe soll dabei durch eine der Ziffern {0,...,9}
belegt werden, wobei jede Ziffer nur für einen Buchstaben verwendet und der Buchstabe M nicht durch die Ziffer Null belegt werden sollte.
Das hier vorgestellte Prolog-Programm implementiert einen Brute-Force-Algorithmus, der als Datenstruktur Listen benutzt. Die Liste der in der Gleichung vorkommenden Buchstaben wird mit allen Permutationen der Ziffern {0,...,9} instanziiert
(Zeile 5). Die Richtigkeit der Gleichung wird in Zeile 6 überprüft und ggf. wird die
Lösung für MONEY ausgegeben (Zeile 7).
Es sei darauf hingewiesen, dass die Prädikate perm(_,_). (Zeile 1, 2) und das
dafür benötigte Prädikat select(_,_,_). (Zeile 3, 4) lediglich aus Gründen der
Vollständigkeit mit angegeben wurden. In nahezu allen Implementierungen von Prolog liegt bereits ein Built-In-Prädikat zur Erzeugung von Permutationen vor.
Es folgt der Quellcode zur Wissensbasis:
1 perm ([] ,[]) .
2 perm ( Liste ,[ X | Perm ]) : - select (X , Liste , Rest ) , perm ( Rest , Perm ) .
3
select (X ,[ X | Rest ] , Rest ) .
4
select (X ,[ Kopf | Liste ] ,[ Kopf | Rest ]) : - select (X , Liste , Rest ) .
5
generiere (S ,E ,N ,D ,M ,O ,R , Y ) : - perm ([ S ,E ,N ,D ,M ,O ,R ,Y ,_ , _
] ,[1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,0]) .
19
Kapitel 5: Zusammenfassung und Fazit
6
gleichung (S ,E ,N ,D ,M ,O ,R , Y ) : - ( S *1000+ E *100+ N *10+ D *1) + ( M
*1000+ O *100+ R *10+ E *1) =:= ( M *10000+ O *1000+ N *100+ E *10+ Y *1) .
7
loese : - generiere (S ,E ,N ,D ,M ,O ,R , Y ) , gleichung (S ,E ,N ,D ,M ,O ,R ,
Y ) , not ( M =:=0) ,! , write ( M ) , write ( O ) , write ( N ) , write ( E ) , write
(Y).
Aufgerufen wird das Programm mit der Anfrage ?- loese. am Prompt. Der Interpreter bestimmt daraufhin ein mögliches Ergebnis und gibt dieses aus:
1 ? - loese .
10652
true .
Aus dem Ergebnis lassen sich die Belegungen für die verschiedenen Buchstaben
in MONEY ablesen. Auf Wunsch könnte natürlich auch die Belegung jedes einzelnen
Buchstaben durch Anpassung von Zeile 7 ausgegeben werden.
Es sei an dieser Stelle noch auf den Cut in Zeile 7 hingewiesen. Dieser verhindert,
dass das Ergebnis ein zweites Mal ausgegeben wird. Dieses würde dadurch geschehen,
dass es eine weitere Permutation der Ziffern {0,...,9} gibt, die lediglich die Positionen
der nicht benötigten Ziffern 3 und 4 ändert1 .
5
Zusammenfassung und Fazit
Nachdem innerhalb dieser Arbeit die Entstehungsgeschichte aus dem Ursprung in
der Logik, der Aufbau von Programmen und die Funktionsweise des Interpreters der
Programmiersprache Prolog erläutert sowie auch die typischen Anwendungsgebiete
herauskristallisiert wurden, sollen abschließend noch einmal auf Vorteile von Prolog
eingegangen und schließlich Gründe für das bisherige Scheitern identifiziert werden.
Durch die enge Verbindung der Programmiersprache zur Logik und damit zur Mathematik lassen sich im Gegensatz zu imperativen Programmiersprachen häufig Korrektheitsbeweise über Programme führen, so dass für kritische Anwendung in dieser
Hinsicht ein großer Vorteil besteht. Wie im Kapitel 4.1 zu Expertensystemen aufgezeigt, ist es in Prolog möglich den Quellcode, d. h. im Rahmen von Prolog die
Wissensbasis, dynamisch zur Laufzeit zu verändern, so dass es möglich ist PrologProgramme lernfähig zu gestalten. Diese Eigenschaft war und ist insbesondere im
Bereich der künstlichen Intelligenz eine wünschenswerte Eigenschaft einer Programmiersprache.
1
Gesamte Gleichung: 9567 + 1085 = 10652, die Ziffern 3 und 4 wurden also nicht benötigt
20
Kapitel 5: Zusammenfassung und Fazit
Prolog zeigt seine Stärken in logischen Problemstellungen und ist speziell für die
Anwendungsgebiete der künstlichen Intelligenz entwickelt worden, jedoch wurde der
Programmiersprache in den 1970er und 1980er Jahren durch Neuronale Netze ein
starker Konkurrent in diesem Bereich entgegen gestellt. Ein weiterer Punkt, der Prolog ins Hintertreffen geraten ließ, ist der Fakt, dass die Ausführungsgeschwindigkeit
im Vergleich zu Programmen in imperativen Sprachen meist geringer ist. Auch der
in Kapitel 3.4 vorgestellte Cut zur Effizienzsteigerung kann dieser Tatsache nicht
entscheidend entgegenwirken. Neben den bereits genannten Nachteilen eignet sich
Prolog zudem nicht sehr gut, um arithmetische Operationen, die Grundbestandteile
vieler Programme darstellen, auszuführen.
Bedauerlicherweise sind selbst die in Kapitel 1.2 genannten ISO-Standards noch
nicht in allen Prolog-Systemen umgesetzt, so dass weiterhin auf eine Konvergenz
zu warten bleibt. Als letzter Punkt seien die lange Zeit zueinander inkompatiblen
Prolog-Systeme, die für einen größeren Nutzerkreis sicherlich nicht förderlich waren,
angeführt.
Alle genannten Gründe leisteten ihren Beitrag dazu, dass das von der japanischen
Regierung 1982 mit einem Budget von 400 Millionen Dollar initiierte, international
beachtete Projekt zu den Rechnersystemen der 5. Generation“ 1992 für geschei”
tert erklärt wurde [FG92]. Während alle vorherigen Rechnergenerationen auf eine
Erhöhung der Anzahl der logischen Bausteine in einer einzelnen CPU setzten, sollten
viele parallel arbeitende Prozessoren in Kombination mit einer logischen Programmiersprache (Prolog) die neue Architektur bestimmen.
Betrachtet man die Entwicklung der heutigen Rechnerarchitekturen in Richtung
Parallelität, so mag der Satz Either it [the Fifth Generation Project] was a failure,
”
or it was ahead of its time.“ 2 [FG00] zum Nachdenken anregen.
Als Fazit bleibt zu sagen, dass in Prolog die Möglichkeit besteht, Probleme aus speziellen Bereichen schneller, einfacher und eleganter lösen zu können. Es gibt jedoch
auch eine Vielzahl von Problemen, für die Prolog nur bedingt einsetzbar ist und in
denen andere Programmiersprachen ihre Stärken ausspielen können.
2
Entweder es [das 5. Generation Projekt] war ein Fehlschlag, oder es war seiner Zeit voraus.“
”
21
Kapitel A: Anhang
A
Anhang
A.1
Code-Beispiel Stammbaum
/* Welche Menschen gibt es in unserer " Welt "? */
mensch ( florian ) .
mensch ( thomas ) .
mensch ( reinhold ) .
5
mensch ( doris ) .
mensch ( hermann ) .
mensch ( katharina ) .
/* Die Beziehungen innerhalb der Familie väterlicherseits .
vater ( reinhold , florian ) sagt aus : Reinhold ist der Vater
von Florian . */
10
vater ( reinhold , florian ) .
vater ( reinhold , thomas ) .
vater ( hermann , reinhold ) .
/* Die Beziehungen innerhalb der Familie mü tterli cherse its .
mutter ( doris , florian ) sagt aus : Doris ist die Mutter von
Florian . */
15
mutter ( doris , florian ) .
mutter ( doris , thomas ) .
mutter ( katharina , reinhold ) .
/* Defintion von Eltern : X ist ein Elternteil von Y , wenn es
entweder ein X gibt , sodass X Vater von Y ist oder es ein
X gibt , sodass X Mutter von Y ist . */
20
elternteil (X , Y ) : - vater (X , Y ) .
elternteil (X , Y ) : - mutter (X , Y ) .
/* Defintion von Vorfahren : X ist ein Vorfahre von Y , wenn er
entweder ein direkter Elternteil von Y ist , oder es gibt
einen Elternteil Z von Y , der selbst widerum X als
Vorfahren hat . */
25
vorfahre (X , Y ) : - elternteil (X , Y ) .
vorfahre (X , Y ) : - elternteil (Z , Y ) , vorfahre (X , Z ) .
22
Kapitel A: Anhang
A.2
Wahrheitstabelle zur Resolutionsprüfung
Wahrheitstabelle zur Formel ¬a ∧ e ∧ c ∧ (d ∨ ¬e) ∧ (b ∨ ¬c ∨ ¬d) ∧ (a ∨ ¬b):
a
b
c
d
e
¬a
e
c
(d ∨ ¬e)
(b ∨ ¬c ∨ ¬d)
(a ∨ ¬b)
Gesamt
0
0
0
0
0
1
0
0
1
1
1
0
0
0
0
0
1
1
1
0
0
1
1
0
0
0
0
1
0
1
0
0
1
1
1
0
0
0
0
1
1
1
1
0
1
1
1
0
0
0
1
0
0
1
0
1
1
1
1
0
0
0
1
0
1
1
1
1
0
1
1
0
0
0
1
1
0
1
0
1
1
0
1
0
0
0
1
1
1
1
1
1
1
0
1
0
0
1
0
0
0
1
0
0
1
1
0
0
0
1
0
0
1
1
1
0
0
1
0
0
0
1
0
1
0
1
0
0
1
1
0
0
0
1
0
1
1
1
1
0
1
1
0
0
0
1
1
0
0
1
0
1
1
1
0
0
0
1
1
0
1
1
1
1
0
1
0
0
0
1
1
1
0
1
0
1
1
1
0
0
0
1
1
1
1
1
1
1
1
1
0
0
1
0
0
0
0
0
0
0
1
1
1
0
1
0
0
0
1
0
1
0
0
1
1
0
1
0
0
1
0
0
0
0
1
1
1
0
1
0
0
1
1
0
1
0
1
1
1
0
1
0
1
0
0
0
0
1
1
1
1
0
1
0
1
0
1
0
1
1
0
1
1
0
1
0
1
1
0
0
0
1
1
0
1
0
1
0
1
1
1
0
1
1
1
0
1
0
1
1
0
0
0
0
0
0
1
1
1
0
1
1
0
0
1
0
1
0
0
1
1
0
1
1
0
1
0
0
0
0
1
1
1
0
1
1
0
1
1
0
1
0
1
1
1
0
1
1
1
0
0
0
0
1
1
1
1
0
1
1
1
0
1
0
1
1
0
1
1
0
1
1
1
1
0
0
0
1
1
1
1
0
1
1
1
1
1
0
1
1
1
1
1
0
23
Kapitel A: Anhang
A.3
Abarbeitungsreihenfolge von Anfragen an den PrologInterpreter (trace)
Hinweis zu den Angaben Call, Redo, Exit und Fail:
• Call: Beginn eines neuen Teilbeweises.
• Redo: Wiederholung eines Teilbeweises mit anderer Variableninstanziierung.
• Exit: Erfolgreiches Beenden eines Teilbeweises.
• Fail: Scheitern eines Teilbeweises.
Des Weiteren sei innerhalb des trace auf das _L165, welches die interne Repräsentation
einer Variablen darstellt, und das creep (zu Deutsch: schleichen, kriechen), welches
den Programmfluss widerspiegelt, hingewiesen.
? - trace , vorfahre ( hermann , florian ) .
Call : (9) vorfahre ( hermann , florian ) ? creep
Call : (10) elternteil ( hermann , florian ) ? creep
Call : (11) vater ( hermann , florian ) ? creep
Fail : (11) vater ( hermann , florian ) ? creep
Redo : (10) elternteil ( hermann , florian ) ? creep
Call : (11) mutter ( hermann , florian ) ? creep
Fail : (11) mutter ( hermann , florian ) ? creep
Redo : (9) vorfahre ( hermann , florian ) ? creep
Call : (10) elternteil ( _L165 , florian ) ? creep
Call : (11) vater ( _L165 , florian ) ? creep
Exit : (11) vater ( reinhold , florian ) ? creep
Exit : (10) elternteil ( reinhold , florian ) ? creep
Call : (10) vorfahre ( hermann , reinhold ) ? creep
Call : (11) elternteil ( hermann , reinhold ) ? creep
Call : (12) vater ( hermann , reinhold ) ? creep
Exit : (12) vater ( hermann , reinhold ) ? creep
Exit : (11) elternteil ( hermann , reinhold ) ? creep
Exit : (10) vorfahre ( hermann , reinhold ) ? creep
Exit : (9) vorfahre ( hermann , florian ) ? creep
true .
24
Literaturverzeichnis
Literatur
[Be86] F. Belli: Einführung in die logische Programmierung mit Prolog, Bibliografisches Institut Mannheim, 1986.
[Be88] F. Belli: Prolog-Systeme in der Praxis, Mannheim, 1988.
[Bo87] Wilhelm Bolkart: Programmiersprachen der 4. Und 5. Generation, Hamburg,
1987.
[CM03] William F. Clocksin, Christopher S. Mellish: Programming in Prolog, Springer, 2003.
[CL90] R. Cordes, R. Kruse, H. Langendörfer, H. Rust: Prolog: Eine methodische
Einführung, Vieweg, 1990.
[KS88] Hans Kleine Büning, Stefan Schmittgen: Prolog: Grundlagen und Anwendungen, Teubner, 1988.
[KS89] Esther König, Roland Seiffert: Grundkurs Prolog fur Linguisten, UTB Linguistik, 1989.
[Sch00] Uwe Schöning: Logik für Informatiker, Spektrum, 2000.
[Sa89] Dr. Stuart E. Savory: Expertensysteme: Nutzen für Ihr Unternehmen, R.
Oldenbourg Verlag, 1989.
[IF08] Applikationen, die auf IF/Prolog basieren
URL: http://www.ifcomputer.de/Consulting/home de.html
Abrufdatum: 04. März 2009.
[ISO95] International Organization for Standardization
URL: http://www.iso.org/iso/iso catalogue/catalogue tc/cataloguedetail.htm?csnumber=21413
Abrufdatum: 04. März 2009.
Der Originaltext zum ISO Standard ist nicht frei zugänglich.
Einen Überblick von J.P.E. Hodgson über den ISO Standard (Prolog: The ISO
Standard Documents) gibt es hier:
URL: http://pauillac.inria.fr/ deransar/prolog/docs.html
Abrufdatum: 04. März 2009.
25
Literaturverzeichnis
[ISO00] International Organization for Standardization
URL: http://www.iso.org/iso/iso catalogue/catalogue tc/catalogue detail.htm?csnumber=20775
Abrufdatum: 04. März 2009.
Der Originaltext zum ISO Standard ist nicht frei zugänglich.
[FG00] Fifth Generation Project
URL: http://encyclopedia.vbxml.net/Fifth Generation Computer
Abrufdatum: 04. März 2009.
[FG92] New York Times, 05.06.1992
URL: http://query.nytimes.com/gst/fullpage.html?res=9E0CE1DB1031F936A35755C0A964958260
Abrufdatum: 04. März 2009.
26

Documentos relacionados