Steckbrief
image: prolog-logo.png kind: steckbrief curriculum: "Oberstufe: Vertiefung Applikative Programmierung (logisch)" topics: [programmiersprachen, geschichte]

Prolog (1972)

Prolog entstand 1972 in Marseille bei Alain Colmerauer und Philippe Roussel, die einen Computer Fragen auf Französisch beantworten lassen wollten. Ein Prolog-Programm sagt nicht, was der Computer der Reihe nach tun soll, sondern was gilt: Fakten und Regeln. Dann stellt man Anfragen, und Prolog sucht die Antworten selbst. In den 1980er Jahren war Prolog eine der Sprachen der Künstlichen Intelligenz, und Japan setzte in seinem großen Projekt der »Computer der fünften Generation« auf logische Programmierung. Heute steckt logische Programmierung in Typprüfern, Datenbanken und Planungssystemen. Hier benutzt du SWI-Prolog, eine freie Umsetzung aus Amsterdam.

Alain Colmerauer (1941–2017), französischer Informatiker, Professor in Marseille. Er wollte, dass ein Computer Fragen auf Französisch versteht und aus Sätzen wie »Katzen töten Mäuse« und »Tom ist eine Katze« selbst schließt, was Tom tut. Dafür schrieb er 1972 mit Philippe Roussel eine Sprache, in der ein Programm aus solchen Aussagen besteht: Prolog, von »programmation en logique«. Wie man logische Aussagen als Programm lesen kann, hatte Robert Kowalski in Edinburgh gezeigt, mit dem er 1971 und 1972 in Marseille zusammenarbeitete.

Das Foto zeigt ihn um 1970 in Montreal, in der Gruppe, mit der er an einem Programm zum Übersetzen zwischen Englisch und Französisch arbeitete; er hält gerade eine Ausgabe seiner Q-Systeme in der Hand, aus denen später Prolog wurde. Noch später baute er Prolog so aus, dass es auch mit Zahlen und Bedingungen rechnet, wie in einem Sudoku, das Prolog nicht durch Ausprobieren löst, sondern indem es unmögliche Zahlen streicht.

Diese Seite zeigt Prolog an drei kurzen Programmen, wie die anderen Seiten zu Programmiersprachen. Wie man in Prolog wirklich denkt, mit Fakten, Regeln, Rekursion und Backtracking, zeigt das Projekt Logisch programmieren mit Prolog.

1. Hello, world!

Öffne ein Terminal mit StrgJ und starte SWI-Prolog mit swipl:

Im Terminal begrüßt SWI-Prolog mit »Welcome to SWI-Prolog« und seiner Version und wartet hinter ?- auf eine Anfrage.

Hinter ?- wartet Prolog auf eine Anfrage. Gib writeln('Hello, World!'). ein, mit dem Punkt am Ende, und drücke Enter. Prolog schreibt die Zeile und antwortet dann true.: Die Anfrage ist gelungen. Mit halt. beendest du Prolog.

Ein Programm in einer Datei

Beende Prolog mit halt. und lege im Terminal einen Ordner für deine Prolog-Programme an:

mkdir -p /workspace/prolog
cd /workspace/prolog

Lege dann mit StrgAltN eine neue Datei an, schreib hinein:

:- initialization(main, main).

main :-
    writeln('Hello, World!').

und speichere sie mit StrgS als /workspace/prolog/hello.pl. Die erste Zeile sagt: Wenn die Datei geladen ist, rufe main auf und beende danach Prolog. main :- … ist eine Regel: main gilt, wenn writeln('Hello, World!') gilt.

Die Endung .pl benutzt auch Perl, eine ganz andere Sprache. Im Ordner prolog zeigt Visual Studio Code eine solche Datei als Prolog, farbig; anderswo hält es sie für Perl:

hello.pl im Editor mit farbiger Syntax: die Zeile mit initialization, darunter die Regel main mit writeln.

Führe das Programm im Terminal aus:

swipl hello.pl

Im Terminal gibt swipl hello.pl die Zeile Hello, World! aus.

Aufgabe 1Hello, World!

Speichere dein erstes Programm als /workspace/prolog/hello.pl und führe es dort mit swipl hello.pl aus.

Tipp

Ein weißer Punkt am Reiter der Datei heißt, dass sie noch nicht gespeichert ist.

Fehler finden und beheben

Schreib in hello.pl statt writeln einmal writln, speichere und führe das Programm wieder aus. Lies, was SWI-Prolog meldet:

Aufgabe 2Was es nicht gibt

SWI-Prolog meldet Unknown procedure: und dahinter, was es nicht kennt. Was steht dort, mit dem Schrägstrich?

Tipp

Die Meldung steht in der ersten Zeile, die mit ERROR: beginnt.

Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.

swipl meldet: ERROR: /workspace/prolog/hello.pl:1: user:main catch/3: Unknown procedure: writln/1, darunter: However, there are definitions for: writeln/1 und writeln/2.

Ein Prädikat heißt in Prolog mit seinem Namen und der Zahl seiner Argumente: writln/1 ist writln mit einem Argument. Das gibt es nicht, aber SWI-Prolog kennt eines mit fast demselben Namen und schlägt es vor. Denk daran, den Fehler wieder zu beheben.

2. Primfaktorzerlegung

Im zweiten Beispiel zerlegt Prolog eine Zahl in ihre Primfaktoren. Statt einer Schleife gibt es Regeln, die sich selbst aufrufen: factors(N, D, Fs) probiert den Teiler D, und passt er nicht, ruft es sich mit D + 1 wieder auf. Gerechnet wird mit is. Erstelle im Ordner prolog eine neue Datei factor.pl:

:- initialization(main, main).

% factors(N, Fs): Fs are the prime factors of N, smallest first
factors(N, Fs) :-
    factors(N, 2, Fs).

factors(1, _, []) :- !.
factors(N, D, [N]) :-
    D * D > N, !.
factors(N, D, [D | Fs]) :-
    N mod D =:= 0, !,
    M is N // D,
    factors(M, D, Fs).
factors(N, D, Fs) :-
    E is D + 1,
    factors(N, E, Fs).

main :-
    writeln('Please enter the number to factorise:'),
    read_line_to_string(user_input, Line),
    number_string(N, Line),
    factors(N, Fs),
    format("Prime factors: ~w~n", [Fs]).

swipl factor.pl fragt nach einer Zahl und gibt für 360 die Primfaktoren [2,2,2,3,3,5] aus.

Prolog rechnet mit beliebig großen ganzen Zahlen. Probier 2 ** 100 aus: Starte swipl und gib X is 2 ** 100. ein.

Vermutung 3Eins plus zwei

Was antwortet Prolog auf ?- X = 1 + 2.? Überleg erst, dann probier es in swipl aus.

Eins plus zwei

Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.

= rechnet nicht: Es macht beide Seiten gleich, und X wird zum Term 1+2, einem Baum aus + mit den Zweigen 1 und 2. Erst is rechnet den Term rechts aus: X is 1 + 2. ergibt X = 3.

3. Bubblesort

Im dritten Beispiel sortiert Prolog eine Liste von zehn Zufallszahlen mit Bubblesort. Es gibt keine Variable, die sich ändert: swap macht aus einer Liste eine neue, in der das erste Paar in falscher Reihenfolge vertauscht ist, und bubble_sort macht das, solange es so ein Paar gibt. Gibt es keines mehr, scheitert swap, und die zweite Klausel von bubble_sort sagt: Dann ist die Liste sortiert. Das ! nach swap verhindert, dass Prolog später noch andere Vertauschungen ausprobiert.

:- initialization(main, main).

% bubble_sort(List, Sorted): swap a pair in the wrong order as long as
% there is one
bubble_sort(List, Sorted) :-
    swap(List, Swapped), !,
    bubble_sort(Swapped, Sorted).
bubble_sort(Sorted, Sorted).

% swap(List, Swapped): Swapped is List with the first pair X, Y swapped
% for which X > Y
swap([X, Y | Rest], [Y, X | Rest]) :-
    X > Y.
swap([Z | Rest], [Z | Swapped]) :-
    swap(Rest, Swapped).

random_number(X) :-
    random_between(0, 99, X).

main :-
    length(List, 10),
    maplist(random_number, List),
    format("Original list: ~w~n", [List]),
    bubble_sort(List, Sorted),
    format("Sorted list: ~w~n", [Sorted]).

Speichere es als bubblesort.pl im Ordner prolog und führe es aus:

swipl bubblesort.pl gibt eine Liste von zehn Zufallszahlen aus und darunter dieselbe Liste sortiert.

Ausprobieren: Starte swipl, lade das Programm mit [bubblesort]. (so ruft es main nicht auf) und frag bubble_sort([3, 1, 2], S). Nimm dann das ! aus bubble_sort heraus, lade mit make. neu, frag noch einmal und drück nach jeder Antwort ;. Achte darauf, welche Listen Prolog jetzt noch für sortiert hält.
Aufgabe 4Die größte zuerst

Ändere prolog/bubblesort.pl so, dass bubble_sort absteigend sortiert, die größte Zahl zuerst.

Tipp

swap vertauscht ein Paar X, Y, wenn X > Y gilt. Welche Bedingung braucht es, damit die größere Zahl nach vorn kommt?

Nächster Tipp

Ein einziges Zeichen in der Klausel von swap mit X > Y entscheidet, wann zwei Nachbarn vertauscht werden.

4. Zusammenfassung

Du hast an drei Beispielen gesehen, wie ein Prolog-Programm aussieht und wie du es ausführst. Prolog ist nicht dafür gemacht, Schritte nacheinander aufzuschreiben; seine Stärke zeigt es, wenn du beschreibst, was gilt, und Prolog suchen lässt. Wie das geht, zeigt das Projekt Logisch programmieren mit Prolog: eine Familie über fünf Generationen, Listen, die rückwärts rechnen, und die Bezirke Berlins in vier Farben. Das Handbuch von SWI-Prolog beschreibt jedes eingebaute Prädikat.