Prolog oder die unendlichen Weiten der Logik

Seite 4: Anwendungsfälle für Prolog

Inhaltsverzeichnis

Logische Strukturen und Pattern Matching machen Prolog zu einer idealen Sprache für Compiler- und Interpreter-Bau. Der folgende Code soll das illustrieren. Es geht darum, das Kartenspiel jetzt interaktiv zu gestalten.

% A, P sind player Strukturen player(Nummer, Spielfeld), je für aktiven und passiven Spieler
play(A, P, go) :-
A = player(Num, _),
format("Player ~d <playCard> or <stop> ", [Num] ),
read(Command),
do(Command, A, P, A2, P2, Finish),
nextPlayer(A2, P2, A3, P3),
play(A3, P3, Finish).

play(_, _, stop).

do(stop, A, P, A, P, Finish) :-
call(stop, A, P, Finish).

do(playCard, A, P, A2, P, Finish) :-
call(playCard, A, A2, Finish).

do(showDeck, A, P, A, P, go) :-
showDeck(L),
format("Current Deck: ~p\n", [L]).

play liest einen Befehl von der Kommandozeile ein. Die passende do(...)-Regel führt dann die notwendigen Aktionen aus (prozedurale Sicht) oder wendet weitere Regeln an (logische Sicht). Eine übliche Technik ist es, den Kontext der Ausführung vor und danach mitzugeben. In dem Beispiel ist das die player(...)-Struktur, die auch das Spielfeld eines Spielers enthält. Nach Ausführung des Kommandos werden aktiver und passiver Spieler vertauscht, und es geht in die nächste Runde per Rekursion.

Das call(FunktorName, Arg1, Arg2...)-Prädikat gibt Prolog dynamische Aspekte, ähnlich den interpretierenden Sprachen. call wirkt, als würde statt dessen die Regel funktorName(Arg1, Arg2,...) geschrieben stehen. Ein sehr inspirierendes Beispiel für Prolog als Prototypensprache ist ein Papier von Joe Amstrong und Kollegen. Es beschreibt, wie Erlang als Prototyp in Prolog begann. Prolog kann auch wunderbar sich selbst interpretieren oder der Prolog-Interpreter um neue Funktionen erweitert werden. Hier sei auf die Literaturliste verwiesen.

In den obigen Beispielen wurde die Schreibweise A < B verwendet. Prolog kennt aber eigentlich nur Funktoren, so dass dieser Ausdruck <(A, B) lauten müsste. Hier hilft die Definition von Operatoren. Eine solche Definition wäre zum Beispiel durch die Direktive :- op(Priorität, Praefix/Postfix/Infixmuster, "<"). möglich. Mit dieser Technik lassen sich leicht lesbare Sprachkonstrukte für den Interpreterbau erstellen.

Auch sehr schön ist die Möglichkeit, Funktoren "zusammenzubauen". Das Prädikat functor(Term, Name, N) ist wahr, wenn Term ein Funktor mit Name name ist, mit N Argumenten. Oder: functor(Term, meinFunc, 3) instanziert Term mit Funktor meinFunc(_,_,_) usw. Ergänzt wird dies durch das Prädikat arg(N, Term, Value), mit dem sich der Wert des N-ten Argumentes eines Terms (und damit Funktors) ermitteln lässt.

Für Prolog ist schon länger ein Standard verfügbar, der ISO/IEC 13211-1:1995. Der Interessierte kann aus einem Angebot von freien und kommerziellen Implementationen wählen. Das hier verwendete SWI-Prolog bietet neben einer ISO-Prolog-Implementation viele zusätzliche Pakete. Hierzu gehören Webserver und eine RDF-Bibliothek samt Triplestore. Auch gibt es Weiterentwicklungen von Prolog für Parallelität, Constraint-Programming oder Probabilistische Programmierung. Wikipedia bietet eine gute Übersicht.

Viele Prolog-Systeme sind als Compiler für eine Warren Abstract Machine (WAM) ausgeführt. Ähnlich wie in Smalltalk und anderen Sprachen ist dies eine virtuelle Maschine mit für Prolog günstigem Instruktionssatz. Erstmals beschrieben wurde sie 1983 von dem Informatiker David H.D. Warren in einem Paper.