PROLOG Lernende Systeme WS 10/11 Crashkurs Martin Sticht Stephan Weller SWI Prolog http://www.swi-prolog.org Grundlegendes Grundkonstrukte • Fakten • Regeln • Anfragen Fakten und Regeln kommen in die Programm-Datei Anfragen werden dem Interpreter gestellt Jede Anweisung endet mit „.“ Prolog-Programme werden in SWI mit consult(dateiname). geladen (Dateiname ohne Endung, Punkt nicht vergessen!) Fakten • Fakten sind instanziiert • Instanzen werden klein geschrieben! father(bart, homer). mother(bart, marge). sister(bart, lisa). sister(bart, maggie). brother(lisa, bart). brother(maggie, bart). hasChild(marge). hasChild(homer). Achtung: Kein Leerzeichen zwischen Prädikatname und Klammer Die vorliegenden Fakten so zu definieren kann zu Problemen führen (siehe später) Anfragen (1) father(bart,homer). mother(bart,marge). sister(bart,lisa). sister(bart,maggie). brother(lisa,bart). brother(maggie,bart). family.pl Variablen werden GROSS geschrieben. Bei Anfragen mit Variablen werden alle möglichen Instanzen für die Variablen ausgegeben. ACHTUNG: Die Instanzen erscheinen nacheinander jedes Mal, wenn ; gedrückt wird Anfragen (2) father(bart,homer). mother(bart,marge). sister(bart,lisa). sister(bart,maggie). brother(lisa,bart). brother(maggie,bart). ?- sister(X,Y). X = bart, Y = lisa ; X = bart, Y = maggie. ?- mother(maggie,X). Action (h for help) ? continue false. Viele Fakten vergessen! Prädikate vielleicht sinnvoller wählen? 1. Bindung 2. Bindung Drücke c für „continue“ oder a für „abort“ oder e für „exit“ Regeln (1) <Konklusion> :- <Bedingung1>, <Bedingung2>, ... Wie Logik (nur andersrum): Konklusion Bedingung1 /\ Bedingung2 /\.... • :- steht für • , steht für /\ Für Regeln werden Variablen verwendet: father(X,Y) :- gender(Y, male), parent(X,Y). Y ist Vater von wenn Y männlich ist UND Y Elternteil von X ist Regeln (2) ?- sister(X,Y). X = bart, Y = lisa ; X = bart, Y = maggie ; X = lisa, Y = maggie ; X = maggie, Y = lisa ; false. father(X,Y) mother(X,Y) grandpa(X,Y) child(X,Y) sister(X,Y) :::::- Neue Fakten: parent(bart, homer). parent(bart, marge). parent(lisa, homer). parent(lisa, marge). parent(maggie, homer). parent(maggie, marge). parent(homer, ape). gender(bart, male). gender(lisa, female). gender(maggie, female). gender(homer, male). gender(marge, female). gender(ape, male). gender(Y, male), parent(X,Y). gender(Y, female), parent(X,Y). parent(X,Z), father(Z,Y). parent(Y,X). father(X,Z), father(Y,Z), mother(X,W), mother(Y,W), gender(Y,female), not(X==Y). Regeln (3) Alternativen / ODER-Verknüpfungen schmecktGut(zucker). schmecktGut(X) :- enthaelt(X,zucker). WICHTIG: Der Prolog-Interpreter sucht die Fakten/Regeln von oben nach unten ab. Deshalb immer Fakten VOR Regeln! Es geht auch rekursiv: schmecktGut(zucker). schmecktGut(sahne). schmecktGut(X) :- enthaelt(X,Y), schmecktGut(Y). Auch hier die Fakten als Abbruchbedingungen vor den rekursiven Regeln! Weiteres Negation by failure Werden keine passenden Variablenbindungen gefunden oder gibt es das Faktum nicht ?- brother(simon, bernd). false false. Vergleiche X == Y > < >= not(X == Y) =< Listen (1) • Listen sind eigentlich auch nur zusammengesetzte Terme, bei denen der Funktor ein Punkt ist. • Um die Sache zu vereinfachen, kann man Listen mit eckigen • Klammern notieren: [1,2,’drei’,4.2,X] • Die Punkt-Notation funktioniert aber auch: .(1,.(2,.(3,[]))) • Außerdem gibt es noch die Head-Tail-Notation (wichtig!) in der Form [Erstes|Rest], wobei Erstes das erste Element der Liste ist und Rest der Rest. mylist([1|[2,3,4]]). ?- mylist(X). X = [1, 2, 3, 4]. • weiteres Beispiel: .(4,[5|.(6,[])]) ≡ [4,5,6] Listen (2) Rekursion mit Listen: even([]). even([X,Y|R]) :- even(R). ?- even([1,2,3]). false. last([X],X). last([X|R],Y) :- last(R,Y). ?- even([1,2,3,5]). true. Ablauf even: [1,2,3] even([]). even(X,Y|R) [3] even([]). even(X,Y|R) FALSE Ablauf last: -- FALSE -- X=1, Y=2, R=[3] [1,2], X last[[X],X] -- FALSE last([X|R],Y) -- X=1, R=[2] -- FALSE -- X=3, ..???- [2], X last[[X],X]) TRUE -- X=2 Ohne Funktionen? • Prolog ist nicht funktional! Haskell: last [1,2,3,4] 4 • Prolog behandelt nur Wahrheitswerte! Deshalb Ergebnis als Variable last([1,2,3,4],4) True last([1,2,3,4],X) X = 4 True Cut! (1) Wie ist eigentlich not/1 implementiert? not(X) :- X, !, fail. not(_). fail schlä̈gt immer fehl. Der Cut-Operator (!) heißt so viel wie: An dieser Stelle keine anderen Möglichkeiten ausprobieren. • Genauer: Prolog führt in den Pr ädikaten eine Tiefensucheaus, falls es auf den Cut-Operator trifft, schneidet es alle anderen Möglichkeiten ab (daher der Name). • Steht der Cut am Ende einer Regel, so wird das Prädikat beim Erreichen des ! erfolgreich. Beim evtl. Backtracking werden keine Alternativen für dieses Prädikat gesucht. Durch fail wird ein Misserfolg verzeichnet. Cut! (2) • Wichtigste Funktion: Unnötige Teile des Suchraums abschneiden. • Man spricht auch von einem Green Cut. • Einfaches Beispiel: minimum(X,Y,X) :- X <= Y, !. minimum(X,Y,Y) :- X > Y, !. • Wenn x ≤ y stimmt, wird das zweite Prädikat gar nicht mehr angesehen. • Die Implementation ist also effizienter, ohne logisch etwas zu verändern Cut! (3) • Aber es gibt natürlich auch einen Red Cut. Ein solcher verändert das Ergebnis und kann auch (bei falschem Einsatz) zu unerwünschten Ergebnissen führen. • Beispiel: minimum(X,Y,X) :- X <= Y, !. minimum(X,Y,Y). Was stimmt hier nicht? Was ist z.B. mit minimum(2,5,5).? Listen und Mengen (1) • append(?List1, ?List2, ?List3) List1 an List2 gehängt ergibt List3 • member(?Elem, ?List) Elem ist ein Element von List • last(?List, ?Elem) Elem ist das letzte Element von List • reverse(+List1,-List2) List1 umgedreht ergibt List2 • flatten(+List1,-List2) List2 ist List1 ganz ohne Schachtelungen Listen und Mengen (2) • is_set(+Set) Set ist eine Menge • list_to_set(+List, -Set) Set ist die Menge der Elemente aus List • intersection(+Set1, +Set2, -Set3) Schnitt von Mengen • substract(+Set, +Delete, -Result) Mengendifferenz • union(+Set1, +Set2, -Set3) Vereinigungsmenge • subset(+Subset, +Set) Teilmenge