Prolog („Programming in Logic“, auch frankophon „Prologue“) ist eine Programmiersprache, die maßgeblich von Alain Colmerauer, einem französischen Informatiker, Anfang der 1970er Jahre entwickelt wurde und zur Familie der deklarativen Programmierung zählt. Sie ist eine Vertreterin der logischen Programmiersprachen. Ursprüngliche Prologvarianten arbeiten vollständing auf Basis des Edinburgh Standards, bei aktuelleren Versionen wird dies aber nicht mehr konsequent durchgehalten.
Man kann die Sprache als „Maschinensprache eines Logik-Prozessors“ bezeichnen, da sie auf den mathematischen Grundlagen der Prädikatenlogik beruht. Ein Prolog-Programm ist eine Sammlung von so genannten Horn-Klauseln.
Ein Prolog-Interpreter wurde erstmals in Lisp programmiert.
Das typische erste Programm in Prolog ist nicht wie in prozeduralen Programmiersprachen ein Hallo-Welt-Beispiel, sondern eine Datenbasis mit Stammbauminformationen.
Folgendes Beispiel repräsentiert den Stammbaum einer kleinen Familie. Die Aussage mann(tobias) liest sich als: Tobias ist ein Mann. vater(tobias, frank) wird hier verwendet als: Tobias ist der Vater von Frank.
mann(adam). mann(tobias). mann(frank). frau(eva). frau(daniela). frau(ulrike). vater(adam,tobias). vater(tobias,frank). vater(tobias,ulrike). mutter(eva,tobias). mutter(daniela,frank). mutter(daniela,ulrike).
In einem Prolog-Interpreter können nun interaktiv Anfragen an die Datenbasis gestellt werden. Das Ausführen eines Prolog-Programms bedeutet immer das Stellen einer Anfrage. Das System antwortet entweder mit yes. oder no., abhängig davon, ob die Anfrage bewiesen werden konnte, oder es gibt zusätzlich eine Liste von Variablenbelegungen an. Variablen sind in Prolog alle Token, die mit einem Großbuchstaben beginnen. Beispiel:
?- mann(tobias). yes. ?- mann(heinrich). no. ''?- frau(X). X=eva ; X=daniela ; X=ulrike ; no. (keine weiteren Antworten).
Das System kann nur positive Antworten zu Anfragen geben zu denen es Fakten in der Datenbasis vorliegen hat. Wenn etwas fehlt ist die Antwort no (nein), die bedeutet, dass aufgrund der Datenbank nichts ableitbar ist (Closed world assumption). Im Beispiel oben ist dies durch die Anfrage
?- mann(heinrich). no.
illustriert (heinrich kann in der Datenbasis nicht gefunden werden).
Zusätzlich zu der Möglichkeit, Fakten zu spezifizieren, bietet Prolog die Möglichkeit, Regeln zu formulieren. Der Regeloperator :- ist dabei wie ein umgedrehter Implikationspfeil zu lesen. Beispiel:
grossvater(X,Y) :- vater(X,Z), vater(Z,Y).
Die Regel besagt: X ist Großvater von Y, wenn es ein Z gibt, so dass X Vater von Z ist und Z Vater von Y. Damit ist der Großvater väterlicherseits definiert. Eine zweite Regel für den Großvater mütterlicherseits sieht so aus:
grossvater(X,Y) :- vater(X,Z), mutter(Z,Y).
Regeln mit gleichem Head, das heißt gleichem Term vor dem Regeloperator, werden als oder-verknüpfte Alternativen betrachtet. Jetzt sind Anfragen wie die folgenden möglich:
?- grossvater(adam,ulrike). yes. ?- grossvater(X,frank). X=adam
Ist die Rekursion in den meisten Programmiersprachen nur eine zusätzliche Variante zur Iteration, ist sie bei der Prolog-Programmierung die einzige Möglichkeit, „Schleifen“ zu produzieren. Benötigt man in obigem Beispiel eine allgemeine „Vorfahr“-Relation, wird das wie folgt realisiert:
vorfahr(X,Z) :- elternteil(X,Z). vorfahr(X,Z) :- elternteil(X,Y), vorfahr(Y,Z).
Dies lässt sich wie folgt lesen: X ist ein Vorfahr von Z, wenn X Elternteil von Z ist (Regel 1) oder es ein Y gibt, das Vorfahr von Z ist und gleichzeitig X Elternteil von Y (Regel 2) (Es wurde hier elternteil statt mutter und vater verwendet. elternteil(X,Y) :- mutter(X,Y); vater(X,Y).).
Auch Listen sind ein entscheidender Bestandteil von Prolog. Die meisten Prolog-Implementationen bringen dafür viele Funktionen mit (Anhängen von Werten, Anzahl der Werte, etc.), die sich aber auch alle selbst bauen lassen. In einer gedachten Familienstruktur muss die Anzahl der Kinder ja variabel sein. Folgendes wäre denkbar:
familie(heinz,jutta,*). familie(karl,gertrud,*).
Dann ließen sich z.B. mit einer Abfrage alle Familienväter ohne Kinder anzeigen:
?- familie(X, _, *). X=karl
Eine weitere Eigenschaft und Besonderheit gegenüber anderen Programmiersprachen ist, dass Prolog in der Lage ist während der Laufzeit seine vorhandene Datenbank zu erweitern oder zu löschen. Ein Beispiel für das Löschen eines einzelnen Elements:
auto(bmw,rot). auto(bmw,blau). autofarbe(Automarke,X):-retractone(auto(bmw,_)),auto(Automarke,X).
Die Abfrage:
?- auto(bmw,X).
ergibt (anfänglich) ganz normal:
X=rot X=blau No
Die Abfrage:
?- autofarbe(bmw,X).
würde beim ersten mal:
X=blau No
beim zweiten Mal nur noch:
No
liefern, da die Informationen:
auto(bmw,rot). auto(bmw,blau).
aus der Datenbank gelöscht wurden. Auch ?- auto(bmw,X) liefert jetzt nur noch No. Zum Löschen aller gleichen Elemente (also z. B. auto()) auf einmal benutzt man retractall(), zum Ausgeben asserta() (oben in der Datenbank) und assertz() (unten in der Datenbank).
ABB - CD = EED - - * FD + EF = CE = = = EGD * FH = ???
A bis H stehen jeweils für eine Ziffer 0 bis 9, wobei nicht klar ist, welche Zahl an welchen Buchstaben gebunden ist. Gesucht ist die Zahl, die bei den Fragezeichen stehen muss. Dieses Problem ist in Prolog sehr einfach zu lösen. Man schreibt zunächst eine Regel, die bewirkt, dass A bis H später mit allen möglichen Kombinationen von 0 bis 9 belegt werden (Permutation):
gen(A,B,C,D,E,F,G,H) :- permutation(*,*).
Nun muss man nur die fünf entstehenden Gleichungen (ABB – CD = EED, FD + EF = CE, ABB – FD = EGD, CD – EF = FH und EED * CE = EGD * FH = X) in Prolog-Syntax schreiben:
gl1(A,B,C,D,E) :- ((A * 100 + B * 10 + B) - (C * 10 + D)) =:= (E * 100 + E * 10 + D). gl2(C,D,E,F) :- ((F * 10 + D) + (E * 10 + F)) =:= (C * 10 + E). ''gl3(A,B,D,E,F,G) :- ((A * 100 + B * 10 + B) - (F * 10 + D)) =:= (E * 100 + G * 10 + D). gl4(C,D,E,F,H) :- ((C * 10 + D) - (E * 10 + F)) =:= (F * 10 + H). gl5(C,D,E,F,G,H,X) :- ((E * 100 + E * 10 + D) * (C * 10 + E)) =:= ((E * 100 + G * 10 + D) * (F * 10 + H)), X is ((E * 100 + G * 10 + D) * (F * 10 + H)).
Wenn einen nur X interessiert legt man sich eine Lösungsregel an, die alles zusammenführt und X ausgibt:
loesung :- gen(A,B,C,D,E,F,G,H), gl1(A,B,C,D,E), gl2(C,D,E,F), gl3(A,B,D,E,F,G), gl4(C,D,E,F,H), gl5(C,D,E,F,G,H,X), write(X).
Gibt man nun die Abfrage loesung. ein, wird die Lösung ausgegeben. Wie man sieht, benötigt man zur Lösung dieses Problems fast keine Programmierkenntnisse über Schleifen oder ähnliches, sondern gibt nur die Fakten ein und welches Ergebnis man benötigt. Prolog steht in der Abstraktionshierarchie aus genau diesem Grund über imperativen und objektorientierten Sprachen.
Ein typischer XML-Baum wie
wird unter Prolog als rekursive Liste von Elementen element(TagName, Attribute, Kinder) dargestellt.
''['titel=Peer Gynt', [ element(autor, Ibsen', 'nat=norwegisch', *), ...] ]
Ein sehr einfaches Paradigma (untere drei Klauseln) erlaubt es, jeden Baum rekursiv zu durchlaufen. Folgende Beispiele löschen (oberstes Prädikat mit delete) und konkatenieren (zweites Prädikat von oben mit concat) bestimmte Tags. Der erste Unifikator ist die Operation (delete oder concat), der zweite die zu bearbeitende Struktur, der dritte das spezifierte Tag, der vierte der Ergebnisbaum. append ist ein Befehl zum konkatenieren von Listen.
transform(delete, _, _) | Siblings, DelTag, ResTree) :- transform(delete, Siblings, DelTag, ResTree).
transform(concat, [element(ConTag, Attr, Children1), element(ConTag, _, Children2) | Siblings], ConTag, ResTree) :- append(Children1, Children2, Children), append(Attr, Children), Siblings, DummyResult), transform(concat, DummyResult, ConTag, ResTree).
''% Paradigma. Baum-Struktur rekursiv durchlaufen. transform(_, _, [). transform(Trans, Attr, Children) | Siblings, Tag, ResTree) :- transform(Trans, Children, Tag, ResChildren), transform(Trans, Siblings, Tag, ResSiblings), append(Attr, ResChildren), ResSiblings, ResTree). ''transform(_, _, [Atom).
Stößt der Backtracker bei der Operation delete auf ein Tag, das wie das zu löschende heißt, so wird dieses entfernt und bei den Nachbarn weitergesucht. Ein entsprechender Aufruf ist z. B. transform(delete, Tree, autor, ResTree)., der alle Autoren entfernt.
Ähnlich kann man durch transform(concat, Tree, paragraph, ResTree). alle nebeneinanderstehenden Paragraphen miteinander verschmelzen. Dazu werden zunächst deren Inhalte konkateniert, daraus eine neue Paragraphstruktur erzeugt und diese weiterverarbeitet.
Um Regeln für Parser zu schreiben haben die meisten Prologsysteme einen Präprozessor implementiert, der es erlaubt, die Regeln in einer lesbareren Form zu notieren, die in der Form den Regeln entsprechen, die man verwendet um eine kontextfreie Sprache zu beschreiben. Der Präprozessor ergänzt Platzhalter und erzeugt die oben erwähnten Prolog-Logik-Formeln. Durch Übergabe weiterer Attribute ist es möglich mit Definite Clause Grammars auch komplexere Sprachen als die kontextfreien zu beschreiben.
Referenz: http://www.cs.sunysb.edu/~warren/xsbbook/node10.html
In den 1980er Jahren spielte die Sprache eine wichtige Rolle beim Bau von Expertensystemen. Die Sprache wird auch heute noch in den Bereichen Computerlinguistik und Künstliche Intelligenz verwendet. Außerdem gibt es einige kommerzielle Anwendungen im Bereich des Systemmanagements, bei denen asynchrone Ereignisse (Events) mit Hilfe von Prolog oder darauf basierenden proprietären Erweiterungen verarbeitet werden. Ein Beispiel hierzu ist das Produkt „Tivoli Enterprise Console“ von IBM, das auf BIM-Prolog basiert.
برولوغ | Prolog Prolog | Prolog (programmeringssprog) | Prolog | Prolog Prolog Prolog Prolog Prolog Prolog Prolog | Пролог (язык программирования) | Prolog | ภาษาโปรล็อก | Prolog
This article is licensed under the GNU Free Documentation License.
It uses material from the
"Prolog (Programmiersprache)".
Home Page • arts • business • computers • games • health • hospitals • home • kids & teens • news • physicians • recreation• reference • regional • science • shopping • society • sports • world