Also ich habe eben mit Freude festgestellt,
dass ich den Terminplan durchgegangen bin,
dass wir dieses Semester unglaublich gut in der Zeit legen können,
die das Akademikus, kein Streik.
Also wir haben wirklich alle Termine zur Verfügung gehabt.
Und das gibt uns dann gegen Ende des Semesters tatsächlich noch einen Tag,
wo wir schlichtweg den Stoff wiederholen können und vor der Klausur
nochmal alles durchgehen und sagen können, wo sind die Akzente gewesen?
Was war besonders wichtig? Was sollen wir jetzt zu
diesem Zeitpunkt verstanden haben? Heute ist noch einmal unser Thema
relationaler Programmierstil
Ich denke, selbst für diejenigen, die immer gleich im
Anschluss bei meinem Kollegen Wolfgang Menzel die relationale Programmierung hören,
ist es ganz gut, dass wir diese beiden Programmierstile kontrastieren.
Also ich mache ja praktisch ein paar Foss-Ritt durch die gesamte relationale Programmierung
in zwei Stunden für den Stoff, den er in einem Semester macht.
Das führt automatisch dazu, dass einfach die Akzente gesetzt werden
auf die Punkte, die wichtig sind. Also diejenigen,
die das ganze Semester nichts anderes gemacht haben mit skalationalen Programmierstil,
wird die trotzdem ein bisschen darauf zu achten, dass sie merken,
wo die Unterschiede zwischen diesen beiden Stielen sind, vor allem,
wenn sie am selben Tag zwei unterschiedliche Klausuren zu den verschiedenen Themen schreiben müssen.
Ich wollte mal fragen, wer von denen,
die jetzt hier sitzen, hört, auch rationale Programmierung?
Okay, also Ihnen wird aufgefallen sein, dass wir notgedrungen,
weil wir es im Racket für Scream machen, eine andere Syntax haben.
Würden Sie Wert darauf legen bei den Aufgaben zum relationalen Programmierstil,
schlichtweg die altvertraute Prolog-Syntax zu verwenden? Wir könnten es so machen,
dass wenn Sie jetzt nicht noch üben wollen,
wie schreibt man pro Lob im Recket,
dass wir beim Korrektieren korrigieren, auch gerne aktivieren,
wenn sie stattdessen einfach richtiges Po-Log schreiben.
Sie müssen nur dazuschreiben, was sie gemeint haben.
Also nicht von Zeile zu Zeile wechseln zwischen diesen beiden Stielen.
Also wenn sie zu Anfang erklären, ich mache die Antworten
im richtigen Pro-Log, soll es mal recht sein.
Aber wenn sie erklären, sie will Po-Log für Recket,
soll es uns recht sein.
Bloß bitte nicht mitten in der Zeile den Stiel wechseln.
Das macht das Korrigieren dann schwer. Okay, das letzte Mal
haben wir ja schon eine Viertelstunde so über wichtige Grundbegriffe gesprochen.
Ich steige da trotzdem noch mal kurz ein,
damit wir uns über die Syntax
klar sind
Wir hatten ja zunächst mal gesehen, das Wichtige in diesem Verarbeitungsmodell ist,
dass wir den Rechner als abstrakte Maschine sehen,
der logische und relationale Anfragen zu einer gegebenen Datenbasis beantworten kann.
Und er wird eben bezogen, oft die Welt,
die in seiner Datenbank ist, Closed World Assumption. Wir nehmen an,
die Welt ist geschlossen, es gibt nichts außerhalb dessen,
was in der Datenbank ist und sein Wissen bitte uns sagen,
ob etwas wahr ist oder falsch ist.
Und wenn der Rechner zeigen kann, dass es wahr ist,
würde er uns sagen, mit welchen Variablenbindungen
Die Aussage, die Anfrage war, gemacht werden kann.
Wie zum Beispiel hier, wenn wir auch dem Mörder von irgendjemand fragen.
Wir haben auch gesehen, das letzte Mal beim Vorbesprechen,
dass wir in der Datenbasis zwei Arten von Klauseln haben,
mit dem wir jetzt den Zustand unserer abgeschlossenen Welt beschreiben können.
Und das sind einmal die Fakten,
wo wir einfach nur zu gegebenen Objekten Beziehungen zwischen diesem beschreiben.
Und das zweite für mich eigentlich viel spannendere,
weil das über nationale Datenbanken hinausgeht, ist,
dass wir Regeln beschreiben können, mit denen wir weitere Fakten ableiten können.
Vielleicht noch mal zum Begriff der Closed World Asception oder abgeschlossene Welt.
Also wenn wir in unserer normalen Welt,
wo wir mit allem und jedem rechnen müssen,
die Aussage in die Welt setzen, alle Raben sind schwarz,
haben wir ein Problem.
Ja, wir müssen wirklich nachweisen,
dass wir jeden existenten Raben in der Welt überprüft haben.
Und wir wissen nicht, ob vielleicht doch noch
irgendwo in Bergen das Simala ja ein weißer Rabe herumsitzt.
Also in einer Welt, die nicht abgeschlossen ist,
sind manche Aussagen schwer zu treffen
In der endlichen Welt, der Faktendatenbasis, können wir in
vielen Fällen sagen, ja, alle Raben sind schwarz.
Wir können es nicht tun, wenn wir aus Versehen Regeln formuliert haben, die prinzipiell unbeweisbar sind.
Das sitzt jetzt auch pro Lock nicht vor sich. Okay. Gut,
im regulären Pro Lock, der hat mir noch mal daran erinnert,
schreiben wir ihr Regeln in der Art, erst das Prädikat,
dann Klammer auf und dann Die einzelnen Bestandteile,
die in Beziehung gesetzt werden sollen, aus den Teilmengen,
über die diese Regeln Kreuzprodukte darstellt, in Prolog fürs Gim,
bin ich den einfachen Weg gegangen mit der Prolog in Reckett,
dass ich gesagt habe,
ja, wir müssen die Regeln am besten so schreiben,
dass wir weitgehend unsere Reckets syntags verwenden können.
Und deshalb repräsentieren wir sie schlichtweg als normale Liste.
Klammer auf, nahmen wir das Prädikats.
Und dann die einzelnen Objekte, die in Beziehung gesetzt werden
Regulären ProLog wird es eher so aussehen. Population,
Bevölkerung von San Francisco ist und dann kommt auch noch ein Komma vor,
was für ein Racket auch nicht so gerne haben. Gut,
wir haben das letzte Mal schon an dem Beispiel der Relation geübt,
wer mag wen, die Likes-Renation und haben gesehen,
wir können das schlichtweg nach attraelationaler Datenbanken aufzählen,
nahme der Relation und dann wer mag wen,
die jeweils diese beiden Elemente angeben und für endliche Relationen ist
es eine reine Fleißaufgabe,
das einfach alles reinzuschreiben
Und um es einzutragen in unsere Datenbasis als Zusicherung,
verwenden wir die erste Spracherweiterung. Dieses hier ist ein Sprachelement,
was im normalen Reckett nicht vorkommt. Und ich habe es
als Spracherweiterung implementiert. Es ist ein Makro. Und es wird,
weil es ein Makro ist als Special Form,
zum Sprachumfang hinzugefügt und speziell ausgewertet.
Wir werden in der nächsten Stunde darüber sprechen,
wie wir mit Makro solche Spracherweiterungen machen.
Hier nehmen wir es einfach als gegeben hin. Dieses Makro nimmt die Liste,
die hier folgt und trägt die als Fakt in die Pro-Log-Datenbasis ein.
Ja, das ist das eins der beiden Sprachelemente,
die ich zu Recket hinzufügen musste,
damit wir Pro-Log in Recket implementieren können.
Alles andere ist tatsächlich über Recket selbst gelöst. So,
und also wenn wir wollen, dass solche Zusicherungen eingetragen werden,
müssen wir einfach als Fleißaufgabe einen großen Pfeil schreiben,
wo nacheinander immer dieses Assird-Makro-Assird für sichere Zoom-Makro
aufgerufen wird und dann dieses Element der Relation Likes hinzufügt
Ganz wichtig, aber das letzte Mal betont,
aber kann man nicht oft genug sagen.
Einer der ganz großen Unterschiede zwischen dem relationalen Programmierstil und
dem funktionalen Programmierstil ist die richtungsunabhängigkeit des relationalen Programmierstils.
Wenn wir funktional zwei unterschiedliche Arten von Fragen beantworten wollen,
wer mag denn unseres Handy?
Ja, dann würden wir eine Funktion schreiben, Likes.
Die kriegt das Argument Sandy und dann gibt es uns
eine Liste zurück mit allen,
die Sandy mögen
Und wenn wir jetzt im Gegenzug wissen wollen,
von wem wird der Lee gemocht,
dann würden wir eine zweite Funktion schreiben, Likeers off.
Und die Gegenrichtung abfragen. Wir müssen also für jede Richtung,
in die wir unsere Relation werden, mag wen,
auswerten wollen, müssten wir zwei Funktionen schreiben mit einem funktionalen Programmierstil.
Im relationalen Programmierstil schreiben wir nur eine.
Und die können wir in unterschiedlicher Art verwenden,
eben in die eine Richtung suchen oder in die andere
Die Richtung, in die wir im relationalen Programmierstil unsere Datenbasis durchsuchen geben,
wird dadurch vor, wo wir Variablen eintragen.
Also wenn wir jetzt unser Likes-Prädikat hier haben,
und wir wollen wissen, wer mag denn unsere Sandy,
dann fügen wir eine Variable ein.
Als zweites Argument. Nee, Quatsch, wen mag Sandy?
Und tragen hier die Variable ein und bekommen dann mit jeder Anfrage
eine weitere mögliche Variablenbindung, solange bis das Ripertoire erschöpft ist.
Und für Val Maglie würden wir eben hier eine Variable einfügen
Und bekommen dann Sandy zurück. Das heißt,
den Ablauf eines Programms in Prolog oder im relationalen Programmierstil steuern wir durch unterschiedliche Formende Anfragen,
indem wir eben verschiedene Belegungen, das muss dann hier vorsehen,
Instanzierungsvarianten, sagen wir auf Deutsch, ja.
Welche Variablen sind fest vorgegeben als Konstanten und welche sind offen?
Und das bestimmt, wie die Datenbasis durchsucht wird und was
wir als Antwort bekommen können.
Also hier hätten wir insgesamt bei zwei Variablen vier Instanzierungsvarianten.
Wir können einmal die erste festbelegen
Einmal die zweite festbelegen. Wir können sie alle offen lassen oder alle fest vorgeben.
Also wenn wir hier fragen, likes, cendileed,
dann würden wir einfach ein Yes zurückbekommen, weil den Maxi.
Also vier mit zwei Variablen haben wir schon vier Arten,
wie das Programm aufgerufen werden kann.
Und die zweite Art, die es dann noch spannender macht,
ist die, bei der wir unendliche Relationen durchsuchen können.
Ja, wenn wir weitere Einschränkungen haben wollen und nicht alles
einzeln aufzählen wollen. Also das sind dann die Regeln und
die ermöglichen es uns eben unendliche Relationen zu haben
Und Regeln sehen immer so aus,
dass wir hier einen Kopf haben, in dem es steht,
wenn es darum geht zu beweisen, dass Handy irgendein X-Markt,
dann versuch mal alles zu beweisen, was hier recht steht.
Hier rechts schreiben wir Prämissen hin dafür, dass
diese Anfrage wahr ist. Und hier steht als Prämisse,
ja, also dieses X wird von Sandy gemocht,
wenn dieses X Katzen mag
Und hier rechts können jetzt sehr viele stehen. Und wenn sie
direkt hintereinander stehen, ist das einem implizit eine Konjunktion.
Alles muss wahr sein, damit dies hier erfüllt ist.
Und natürlich muss überall das X, haben wir
das letzte Mal gesehen, Co-Referenz, denselben Variablenwert bezeichnen.
Okay, das hatten wir alle schon besprochen.
Das lassen wir mal weg. Also zur Nomenklatur. Dieser
linke Teilausdruck, der wird eben der Kopf der Klausel genannt.
Und was hier rechts von diesem Operator steht,
das ist der Körper der Klausel
Ja, und unsere Fakten, die wir gesehen haben,
wenn wir die Relation einfach aufzählen,
das sind schlichtweg spezielle Formen der Klauseln,
bei denen wir nur den Kopf hinschreiben.
Und das ist eben wahr, ohne dass irgendeine Prämisse
bewiesen werden muss. Gut, was haben wir denn?
Hier mal versucht zu programmieren. Wir wollen wissen,
wen denn Kim mag. Und Kim ist sehr wählerisch,
da müssen gleich zwei Vorbedingungen erfüllt sein.
Kim mag X, wenn X lieben mag und Kim mag
Wenn X auch ihn mag. Also, mag nur Menschen,
die ihn mögen. Und das stehen jetzt zwei hintereinander und
die sind eben durch und verbunden dadurch implizit. So,
als weiteren wichtigen zentralen Punkt hatten wir das letzte Mal angesprochen,
wie das Binden von Variablen geschieht.
Und dieses Binden von Variablen geschieht durch Unifikation.
Einen Abgleich einer Anfrage mit unserer Datenbasis. Und die Unifikation
versucht rekursiv Variatinbindung zu finden, die die Anfrage erfüllen.
Dabei die Ko-Referenz gewährleisten, das heißt,
wenn immer wir für irgendeinen X einen Wert eingesetzt haben,
muss an allen Stellen derselbe sein und verwendet dazu rekursiv mit Backtracking auch die Regeln,
die versuchen, jetzt Rekursiv,
die Regeln auf der rechten Seite als Teilziel mit Backtracking zu beweisen.
Wir haben sowas ähnliches wie Unifikation schon gesehen,
als wir dieses kleine Eliza-Programmchen durchgesprochen haben.
Und dort haben wir alles Wissen über mögliche Antworten in Form von Regeln
aufgeschrieben. Und die haben wir mit Pattern-Matching durchsucht.
Nochmal zum Unterschied zwischen Pattern-Matching und Unifikation. Beim Pattern-Matching,
da durften die Variablen immer nur in einem Teilausdruck auftauchen.
Und bei der Unifikation,
die in unserem Pro-Log in Recket durch die Funktion Unify implementiert ist,
da ist die Situation symmetrisch,
Variablen dürfen auf beiden Seiten vorkommen
Und zwei Ausdrücke werden als unifizierend betrachtet,
wenn drei Dinge erfüllt sind, die Stelligkeit muss stimmen,
wenn wir hier zwei Klauseln stehen haben,
dann muss sie eben genau so viele Elemente haben,
wir können nicht etwas, was vier Elemente hat,
mit etwas mit fünf Matchen auf diese Weise,
ist die Stillligkeit muss stimmen.
Die Namen der Prädikate, wenn dann ein Prädikat vorkommt,
müssen stimmen. Und wenn gleiche Variable an gleiche Werte
gebunden sind. Ja? Das müsste eigentlich auch entstehen,
dass die Argumente rekursiv auch noch kodifiziert werden. Ja,
hatte ich vorher schon damit gesagt, dass durch die,
also rekursiv bei jedem Ersetzungen muss es natürlich immer wieder geschehen,
aber dies hier bezieht sich jetzt auf das Endresultat.
Also wenn die Kur-Referenz nicht erfüllt ist, haben wir Pech.
Dann geht es nicht. Also die einfachste Form der Unifikation,
wenn wir zum Beispiel hier so einen Ausdruck haben,
Ein Prädikat F und es gibt hier nur ein weiteres Argument,
ja, die Variable X, wieder das Argument,
ein weiteres Argument Y, Stelligkeit, stimmt.
In beiden Fällen haben wir hier zwei Elemente und die Frage ist jetzt,
kann er ein X, einem Y zugewiesen werden?
Klar, das geht, weil wir hier ja Variable haben,
ja. Es funktioniert eben in dem Fall,
wo wir in beide Variablen denselben Wert binden und wenn wir hier
zwei Variablen miteinander unifizieren und sie haben beide noch keinen Wert,
haben wir damit automatisch festgestellt, dass die Gleichheit gegeben sein muss.
Oder X hat schon einen Wert, aber Y hat noch keinen,
dann wird automatisch in diesem Fall Y an denselben Wert gebunden.
Das ist Unifikation, ist die einzige Art,
wie wir im reinen relationalen Programmierstil Wertzuweisungen machen können.
Man kann natürlich aus dem Programmierstil ausbrechen,
die in jeder anderen Sprache auch,
wenn sie nicht General Topes Sprache ist,
dann gibt es immer Schlupflöcher, immer schnell in andere Programmierstile.
Wir werden hier auch gleich eins besprechen. Aber es ist Solange wir
rein referenziell sind, ist die Unifikation wirklich das Einzige,
wie wir Werwerte an Variable minden können.
Okay, das Beispiel hatten wir schon mal durchgesprochen.
Wie programmieren wir jetzt in Prolog? Und das werden wir
gleich an einigen etwas aufwendigeren Programmen durchsprechen. Also wir werden
relevante Relationen als Klauseln in unserer Datenbasis aufschreiben, deklarieren alles,
was wir über unsere Welt wissen und was uns fürs Problem wichtig erscheint.
Und dann stellen wir Anfragen in einem Intropritter und der
wird für uns
die Datenbasis durchsuchen
Und dadurch wird automatisch ein Programm ausgeführt. Also das,
was gewöhnungsbedürftig ist, ist in diesem Programmierstil, dass wir nichts,
aber auch gar nichts tun, was die Reihenfolge der Auswertung beeinflusst.
Ja, im reinen relationalen Programmierstil gehen wir davon aus,
dass der Programm Ablauf vom System bestimmt wird durch Unifikation und Suche.
Und das ist es. Es gibt natürlich für Effizienzfragen im großen Pro-Log Dinge,
mit denen man einen Cut machen kann und einen bestimmten sagen kann,
hier, such nicht weiter, das ist aussichtslos,
hier gehst du in eine Endlosschleife, aber im Wesentlichen
Da kümmern wir uns überhaupt nicht darum,
wie der Ablauf ist. Wir deklarieren nur die Fakten,
sagen, das wollen wir wissen und kriegen die Antwort.
Also wenn die Suche losgeht, dann merkt sie sich an
allen Entscheidungspunkten, wie kann es jetzt weitergehen?
Also sagen wir mal, wir haben da eine Regel stehen,
eine Klausel und die hat drei Prämissen.
So, wir wollen jetzt wieder wissen, wen unsere Susi denn liebt.
Und jetzt stellen wir fest, eine der Prämissen ist,
wir können beweisen, dass Kim ja, dass die Person Katzen liebt.
Jetzt stellen wir fest, in unserer Datenbasis,
Kim liebt irgendjemand und dann kümmert uns vielleicht erst mal drum zu beweisen,
ob Kim auch Katzen liebt und geben das zurück.
Wenn das mit Kim erfolglos war, weil der mag nur Hunde,
Pech gehabt, dann müssen wir an andere überprüfen,
ob die eventuell Katzen mögen.
Ja, das geschieht mit Backdreckung, das genau mit den Entscheidungspunkten gemeint.
So, also die offenen Alternativen werden alle automatisch gemerkt und dann wird er mit Backdrecking reingegangen.
So, und am Ende erfahren wir dann, ja,
sie liebt den und den und auch das Warum durch die Variablenbindung.
Und weil eben im Backdrecking versucht wird,
für die Prämissen zu beweisen, was wahr ist oder nicht,
heißt, dass jeweils immer ein Ziel oder ein Goal,
weil das müssen wir beweisen, damit wir weitere Fakten finden.
Ja, so das zweite Makro, was ich eingebaut habe
als Spracherweiterung von Recket und damit haben wir eigentlich alles,
was man für ein vollständiges Pro-Log im Recket braucht.
Das ist das Makro-Anfrage, ja. Also bisher haben wir
ja nur die Datenbank eingetragen, wir brauchen jetzt auch noch was,
um Fragen stellen zu können.
Und dieses Makro ist beschrieben durch Fragezeichenstrich. Also wenn wir
Im Programm so etwas schreiben, in unserem Recket-Programm, Fragezeichen,
Strich, dann wird eine Funktion, eine Recket-Funktion aufgerufen,
aus einem dieser Pro-Log-In-Racket-Pakete, die ich geschrieben habe.
Und das war die Funktion Top-Level-Proof, die macht genau dieses Spectracking,
wo es mit Unifikationen versucht, jeweils Teilziele abzugleichen.
Und ganz am Ende wird dann werden die Variablen ersetzt durch Werte.
Das macht diese Funktion oder die Plays war's. Das ist
auch eine Racket-Funktion. Und hier werden all die Ziele,
die bewiesen werden sollen, in unserer Anfrage einfach als Liste eingetragen und zwar quotiert.
Eine Frage. Ja, wieso wird das erste Film dann
sofort wieder angeboten? Hat? Hier an der Stelle?
Geht da beim Code und dann wieder antwortet uns? Ja,
also hier werden, hier wird die Liste Goals einzeln,
die Elemente der Liste einzeln reingesetzt.
Und sie wird dabei einmal ausgewertet
Diese einmalige Auswertung wird dann zu einer neuen quotierten Liste zusammengebaut.
Ja, also der Punkt ist, wir haben hier den...
Dies hier ist ein... ja, dieses Backquote,
Top-Level-Proof, also das ist etwas, was wirklich ausgeführt wird.
Goals ist... ich muss diese Dachs hier oben erstmal erklären.
Dieses Untrest ist ein Sprachelement aus Cellos, das hier verwendet
wird.
Und das
Dieses Sprachelement aus zähllos sorgt dafür,
dass wenn eine Funktion aufgerufen wird mit vielen Argumenten,
alle Argumente, die hier nicht am Anfang einzeln genannt werden,
dass die zu einer einzigen Liste zusammengebaut werden.
Dieses und Goals sorgt dafür,
dass diese Liste hier wieder einzeln reingesetzt wird und weil sie
jetzt aber beim Einsätzen
einmal ausgewertet wird
Wollen wir, wenn wir hier hinterher wieder eine quartierte Liste
an die nächste Funktion geben, wollen das Ganze nochmal quatschieren?
Also das,
dieses Zusammenspiel von wann wo wird in einem Makro quotiert und wann nicht,
das ist etwas, was relativ schwierig ist und was es unsicher macht,
über die Makroprogrammierung werden wir das nächste Mal nochmal ausführlicher sprechen.
Hier nehmen wir erstmal als gegeben hin,
MacDev Makro funktioniert in diesem Fall, wir definieren ein Makro,
das heißt Fragezeichen Strich und dem können wir einfach all unsere Ziele übergeben.
Und dann wird versucht, es zu beweisen und Am Ende
werden die Variablen ersetzt und wir kriegen eine Liste und der steht Variable X,
ist Variable Y ist. Was es auch machen muss,
ist, wenn wir verschiedene Anfragen haben mit verschiedenen Variablen,
dass die alle durch eindeutige Variablen ersetzt werden müssen.
Und das wird in dem Replace, war es hier auch gemacht.
Ja, und wir bekommen dann aber die zurück,
die wir ursprünglich geschrieben haben
Ich hatte es schon gesagt, eine Anfrage gilt als wahr,
wenn sie aus den Zusicherungen der Datenbank bewiesen werden kann.
Und wenn das nicht geht, weil einfach die Datenbank
dieses Faktum nicht modelliert hat, dann kommt Falls zurück,
obwohl es in der wahren Welt wahr sein könnte.
Und wenn eine Anfrage jetzt ausgeführt worden ist und das Ergebnis liegt vor,
dann wird ein Yes gedruckt und dann kommt die Liste aller Variablenbindungen,
die gefunden wurden.
So, und jetzt kann es
weitere Lösungen geben
Wenn man jetzt nicht nur die erste Lösung haben möchte,
sondern weitere, gibt man einfach einen Simmikolern ein.
Und damit wird dann automatisch nach den weiteren Lösungen gesucht.
Der Back-Tracking-Baum ist noch da und weiteren Entscheidungspunkte. Und wir können
so oft Simmikolern einen geben, wie weitere Lösungen da sind,
wenn keine mehr gefunden wird, erfahren wir einfach ein unfreundliches Know.
Gut, jetzt gucken wir uns mal ein Beispiel an.
Wir verwenden pro Lock zuerst einfach nur so als relationale Datenbanksprache. Also ehrlich gesagt,
wenn ich irgendwie ein Datenbankproblem bin, Lispo direkt getappt,
nehme ich meistens schlichtweg das kleine Schlupfloch in Pollock and Recket
für solche Art von Modellierung und kann dann von Recket aus auch Datenbankanfragen beantworten.
Wenn es etwas sehr, sehr Aufwendiges ist,
dann schließt man lieber eine echte relationale Datenbank an,
wo das effizienter gelöst ist.
Aber wenn ich zwischendrin bei den relationalen Programmierstil brauche,
dann nehme ich diese beiden kleinen Makros und setze die Datenbank
auf und lasse es da machen.
Gut, dann gucken wir. Und dann schauen wir uns
ein paar aufwendigere Beispiele an,
wo ich ihn zeigen möchte,
was so die Mächtigkeit vom Prolog als deduktive Datenbank ist,
wo wir eben mit Inferenzregeln arbeiten
Gut, mal ein kleines Beispiel, wo wir eine Relation modellieren,
so wie sie es von relationalen Datenbanken ja schon kennen sollten.
Einfach Familienverhältnisse aufschreiben. Diese Relation Parents soll sagen,
Person 1 ist Mutterperson 2 ist Vater und Person 3 ist das Kind.
Und wenn wir diese Relation haben, können wir eben nach Verwandtschaftsgraden fragen.
Ich habe hier meinen kleinen Familienstammbaum für Peter aufgeschrieben,
also Peters Eltern,
sein Vera und Viktor und Veras Eltern Mayer und Martin und Viktors Mona und Mike
und dann haben wir hier noch von Maya,
die Eltern, Nora und so weiter.
Also hier Eltern, Großeltern, Urgroßeltern. Und dann können wir jetzt mal versuchen,
das hier mit ein bisschen Fleiß in Prolock, in Recket of zu schreiben.
So, schon bei den simpelsten Übungen zeigt es sich,
dass es in Prolock essentiell ist,
wegen der richtungsunabhängigkeit bei Relation, das Aufrufschema hinzuschreiben.
Sonst weiß man am Ende nicht mehr, wie rum ist es gemeint.
War Viktor der Vater Vera, die Mutter oder umgekehrt
und wer ist das Kind oder ist das das Kind?
Und das sind die Eltern. Also das Prädikatschema gehört zwingend dazu bei jedem Prolog-Programm,
dass man weiß, wie die Relation zu lesen ist.
Und hier haben wir jetzt diesen Stammbaum, also die
direkten Eltern von Peter, die Großeltern und so weiter.
Und jetzt können wir fragen, was sind denn die Eltern
von Peter, indem wir hier unsere Anfragemakron nehmen?
Also hier war das Assert-Makro, hier haben wir unsere Anfragemakro,
Pairence, wer ist Mutter, wer ist Vater von Peter?
Und wir erfahren Mother Vera, Vater, Victor.
Und weitere Eltern hat er nicht, Pech gehabt, no.
Also das ist das Symmikol dann,
wenn wir das eingeben, keine weiteren Lösungen da,
wir erfahren no
Wenn wir jetzt nach den Großeltern fragen wollen, die sind nicht explizit modelliert,
also müssen wir irgendwie beschreiben, was denn so große Eltern sind.
Und eine Art, das zu machen, ist Großeltern,
sind die Eltern der Eltern, ja? So,
und das können wir, um jetzt alle Großeltern von Peter zu beschreiben,
suchen wir erstmal seine Eltern und sagen,
wer immer es ist, wir brauchen zwei Personen,
Mutter und Vater, such sie mir in der Datenbasis,
die die Eltern von Peter sind.
Aber ich will
die Großeltern wissen
Also will ich die Eltern der Mutter haben, ja,
nehmen wir hier unsere Variable Mutter,
die haben wir hier oben ja eben gefunden und fragen,
nach deren Mutter und Vater, und die taufen wir mal,
weil mir jetzt eine andere Variable-Name brauchen, Grenntmann und Grenntmann,
und für den Vater brauchen wir auch dessen Großeltern,
Oma und Opa.
Und alles drei zusammen muss wahr sein,
und dann erfahren wir eben,
die Großeltern grenntmargrenntpa sind Maya und Martin und Oma und Opa,
und haben damit eben auch unsere Großeltern gefunden
Jetzt kommt hier ein bisschen viel zurück.
Und mein Kollege Wolfgang Mänzel mag es eigentlich nicht gern,
wenn so ein Prädikat mit sehr viel mehr variablen Belegungen antwortet,
als wonach man gefragt hat.
Also kann dann noch versuchen, anonyme Variablen zu finden.
Da gehen wir später mal drauf ein. Und wir können
auch über diese Art schlichtweg eine Relation vollständig aufführen,
aufzählen, indem wir alle Variablen uninstanziert lassen.
Und dann kriegen wir hier die komplette Liste von allen möglichen Variablenbindungen.
Also wir erfahren, jede Person,
die von irgendjemandem eine Mutter ist und die von irgendjemandem ein
Vater ist und wir fahren jede Person, die von irgendjemandem ein Kind ist.
So, also wenn wir jetzt eine unwichtige Variable haben und
die wird nicht gebraucht in der Unifikation.
Ja, also die ist einfach unwichtig. Sie muss nur vorgesehen sein,
damit die Stelligkeit bei der Unifikation stimmt,
aber der Wert ist nicht entscheidend und wird eben auch nicht zur Kurreferenz benutzt.
Der Wert interessiert uns nicht, dann können wir hier in
unserem Brüllock, in Reggaette, einfach ein Fragezeichen reinsetzen.
Wenn wir jetzt nur wissen wollen, wer ist denn die Mutter von Walter?
Ja, dann setzen wir für den Vater hier einfach
das Fragezeichen ein und er sagt, don't care.
Interessiert nicht. Und dann kriegen wir als einzige Antwort die Mutter heraus.
Und das ist Petra. Ja. So eine Standardtechnik bei Datenbanken, wenn Verilationen haben,
die eine große Stelligkeit haben und wir brauchen sie nur mit wenigen Stellen,
mit geringerer Stellenzahl, weil uns eben nur andere Dinge interessieren,
dann projizieren wir die Relation.
Und das Können wir einfach dadurch machen,
indem wir hier mit diesem Don't-Care-Variablen eine neue Relation Mutter von einführen,
hat nur die Variable Mutter und das Kind, ja,
und ruft aber unsere modellierte Elternrelation Parents auf, ja.
Parents mother child und für den Vater haben wir jetzt hier
die Stone Care, ignoriere Variable angesetzt, ne.
Und wir haben eine Vaterrelation als Projektion der Elternrelation,
die ist jetzt auch nur nur zweistellig, einfacher zu handhaben.
Das ist so eine Standardtechnik, die man bei relationalen Datenbank gerne verwendet,
einfach andere Sichten auf anschränkende Sichten, auf die modellierten Relationen verwenden.
So, jetzt versuchen wir mal wirklich ins Backtracking einzutauchen.
Bisher waren unsere Anfragen ja mehr so in endlicher Tiefe und sind noch nicht rekursiv geworden.
Also jetzt waren wir pro Lack wirklich mal als detaktive Datenbank
benutzen und ganz allgemein nach allen Vorfahren von Personenfragen.
Und müssen wir uns überlegen, was ist denn nur ein Vorfahr oder eine Vorfahren?
Gibt es das sofort eigentlich auf Deutsch. Gut,
also Eltern sind entweder Vater oder Mutter, ja,
Großeltern sind Eltern der Eltern und Vorfahren sind Eltern oder Eltern von Vorfahren, ja.
Gut, wie machen wir das? Wir schreiben hier auf Eltern,
sind entweder Mutter vom Kind, ja,
die Relation hatten wir eben eingeführt, die Projektion der Perenz-Relation.
Oder sie sind der Vater vom Kind. Dann führen wir Großeltern
ein, Also Großelternrelation. Irgendein Großelternteil von einem Enkelkind ist gegeben,
wenn diese großes Großelternteil, ein Elternteil ist von einem Elternteil des Kindes.
Und das haben wir hier nochmal beschrieben. Also wir sehen
hier schon, wie die Chorreferenz greift. Also es ist wichtig,
dass jeweils innerhalb dieser Klausel alle Namen für Variablen,
wenn sie gleich geschrieben sind, den gleichen Wert bezeichnen.
Und dann können wir jetzt sagen, was ein Vorfall ist,
der Vorfahre, einer Person, ist entweder das direkte Elternteil, ja.
Von der Person, unsere Parent-Relation hier oben. Und wir,
ach so, das habe ich noch vergessen zu sagen,
ist vielleicht im ersten Moment auch gewöhnungsbedürftig.
Ich bin so dran gewöhnt, dass wir nicht mehr als
erwähnenswert auffällt. Wir haben ja schon gesehen,
dass wir beim schlichten Aufzählen von Klauseln
eben immer wieder denselben Relationennamen hinschreiben
Katzenamen und damit die Fakten zusichern. Und das kann man
natürlich auch für die Berechneten und abgeleiteten Fakten machen,
indem wir Klausel hier mehrfach schreiben.
Also wenn wir verschiedene Varianten zusichern, ist das für Prolock
ein implizites, logisches oder? Diese Relation ist erfüllt,
wenn dieses wahr ist oder wenn das wahr ist,
es ist auch kein Entweder-Oder, das ist schlichtweg das,
wenn beides wahr ist oder mindestens eins davon war.
Also wir können es hier so oft hinschreiben,
das sind einfach Alternativen, die geprüft werden.
Und die Alternative ist hier eben Jemand ist ein Elternteil,
wenn er entweder die Mutter ist, so der der Vater ist.
Und für die Großeltern haben wir jetzt zugesichert, sind sie,
wenn die Eltern der Eltern sind. So, und ein Vorfahre,
hier sagen wir jetzt auch wieder beide Fälle und hier werden wir
rekursiv und da ist es sehr wichtig, wie rum wir das aufschreiben.
Wir haben hier zugesichert ein Vorfahre für eine Person,
ist es, wenn es in der Elternrelation steht.
Und damit haben wir praktisch eine Abbruchbedingung für die Suche festgelegt.
Die alte andere Alternative Wir haben jemanden als Vorfahrer,
wenn er direkt Elternteil ist oder wenn wir rekursiv in die Vorfahrenrelation einsteigen.
Und auch hier ist es wichtig, zuerst die Vorfahrenrelation zu nennen,
damit in dem Fall, wo es terminieren könnte,
im Backtracking zuerst das geprüft wird und nicht zuerst der rekursive Teil.
Und wenn der unendlich ist, kommt man nie dazu,
diese Abbruchbedingungen zu erreichen. Also es ist wichtig,
zuerst Teil, der das Ende festlegen kann,
zu erwähnen, bevor man in die Rekursion einsteigt.
Der Rekursionsabschluss war ganz schnell höher. Ja, ja,
genau. Ja, ja, aber dies führt dazu,
dass die aufgerufen wird. Gut, ja,
fragen wir mal, nach diesen Relationen, jetzt nach der Granierelation,
vier werden direkt in Eltern gesucht und da erfahren wir eben alle vier.
Und die Vorfahren von Mike,
wenn wir jetzt die Vorfahren haben wollen, ja,
dann nehmen wir eben Die Instanziierungsvariante wohl hier der Vorfahrenteil
als Variablik gegeben ist und der Mic-Fest vorgegeben ist.
Ja, und dann erfahren wir in unserer Datenbasis,
kommt nur Nina und iPhones vor.
Wahrscheinlich hätte ich da besser Adam und Eva reinschreiben sollen,
wenn es nur eine Sorte Vorfahren gibt.
Wir können aber dieselbe Relation jetzt für irgendeine Person
im Stammbaum nehmen und alle Nachkommen aufzählen lassen.
Einfach die andere Instanzierungsvariante zuerst. Die Person,
deren Nachkommen wir haben wollen und dann hier da die Variable reinsetzen und sehen dann,
aha, für unsere Maya,
da gibt es zwei Nachkommen,
Vera und Peter
Ja. Okay. Ja, also wir haben jetzt Frohlock
als Datenbanksprache angesprochen, auch berechnetere Nationen.
Und jetzt gucken wir uns mal an,
wie wir das wirklich zum Problemlösen nehmen können.
Und da zuerst ein ganz einfaches Beispiel,
weil wir noch ein bisschen syntaktische Feinheiten erklären müssen,
bevor wir denn dieses komplexere Beispiel
angehen können
Wenn wir so Fragen haben, wie sind zwei Personen verwandt oder so,
da muss ja schon ganz schön kombiniert werden.
Und dem eben modellierten Schimmer hier haben wir Petra und Peter
mit ihren Nachkommen und wir haben die ganzen Vorfahren drin,
nimme an, da steht so alles in unserer Datenbank drin.
Wir haben unsere Zusicherungen über die Eltern und wollen jetzt ein Prädikat haben,
mit dem wir feststellen können, sind zwei Personen Geschwister.
Dieses Geschwisterprädikat, Wie würden wir es umgangssprachlich lösen?
Wir würden zwei Personen als Geschwister betrachten, wenn sie dieselben Eltern haben.
Versuchen wir also das erste Mal. Also, wir wollen wissen,
es ist X mit Y, sind die Bruder und Schwester oder so.
Ja, und das, sagen wir mal, ist gegeben,
wenn die Eltern von X, ja, Mutter, Vater,
dieselben Eltern sind wie die von Y. Mutter, Vater.
So. Und damit es eben dieselben sind, Co-Referenz,
hier steht in beiden Fällen dieselbe Variable M und hier steht
dieselbe Variable F für Vater
Nur die Kinder hier sind verschieden. Wird das gut gehen?
Ist das so die umgangssprachliche Idee? Wir sind Geschwister,
wenn unsere Eltern dieselben sind? Benedikt? Ich weiß es
natürlich jetzt auch nicht aus der anderen Zulesung.
Es ist in dem Fall, wenn es sich in dem Fall schiebt,
wo wir dann rauskriegen, dass jemand sein eigenes Geschwister findet sozusagen.
Und ich weiß nicht, wie sie es hier machen wollen,
Follower oder was ist das, jemand, der noch dahinter schreibt,
exqualifiziert nicht mit Y, also das verquält es ja nicht geil.
Ja, gut vorausgesehen
Also ganz völlig richtig. Benedikt. So, wenn,
wenn mich jetzt hier unser Anfragen,
wer ist denn nun der Bruder von Walter oder Geschwister von Walter
? Dann erfahren wir hier, jede Variable, die das wahrmacht.
Und natürlich können wir Walter hier auch in beiden Fällen,
werden wir feststellen, dass wenn Walter gleich weiter ist,
dass beide Elternrelationen hier ja sagen und wir erfahren hier,
gut, die Geschwister von Walter Wilmer,
Werner Winnie,
und er selbst ist nach unserer Definition
sein eigener Bruder
Das ist irgendwie ein bisschen unschön, aber gut,
wäre komisch, wenn es das nicht wäre. So,
und ja, Bennette hatte jetzt schon eine Idee,
gesagt, wie wir es denn hinkriegen können,
um zu verhindern, dass Walter sein eigener Bruder ist.
Und wir brauchen einfach noch etwas, um in dieser
relationalen Welt zu sagen, zwei Variablen sollen ungleich sein.
Die Gleichheit bringen wir durch die Unifikation. Also wenn wir
hier so eine Gleichheitsrelation, können wir einfach so schreiben,
Gleich ist wahr, wenn für zwei Variablen gilt XX.
So, und das kann nur wahr sein,
weil das hier eine Kurreferenz gegeben ist,
wenn X hier in denselben Wert gebunden ist wie hier.
Also damit haben wir etwas von hinten durch die Brust,
aber so geht es einfach in Pullock gesagt, zwei Variablen sind gleich.
Ja, wenn wir diese Relationen verwenden. Und um jetzt
einen Ungleich hinzukriegen, müssen wir ernsthaft noch eine Legationsrelation einführen.
Das geht anders nicht. Und dieses Not musste ich dann auch noch
fest in Pro-Lock in Recket einbauen und das ist diese Funktion hier.
Und die können wir einfach dadurch realisieren, dass wir hier
das Not-Prädikat aufrufen und sagen, X und Y sind nicht gleich.
Also diesen Ungleichoperator können Sie in Kolock in Recket gern verwenden. Und wenn wir das machen,
dann sieht unsere Geschwister ein Prädikat hier so aus,
dass wir deiner Fragen,
sind die Eltern gleich und ist X Ungleich Y und wenn wir das in der Reihenfolge schreiben,
geht es gut, dann erfahren wir jetzt, dass Wilma,
Werner, Winni Wilfried, die Geschwister sind,
aber Walter ist nicht mehr sein eigener Bruder.
Nur mal zusammenfassend, was wir an elementaren, logischen Formulierungsmöglichkeiten
haben im logischen Programmierstil. Wenn wir ein großes Hund haben wollen,
alle Prämissen müssen erfüllt sein,
dann schreiben wir sie einfach auf die rechte Seite der Klausel,
als Ziele hintereinander weg und der gesamte Ausdruck wird nur wahr,
wenn alle erfüllt sind
Wenn wir Alternativen haben wollen, dann schreiben wir einfach mehrere Klauseln.
Das ist dann ein oder entweder die eine Art wird erfüllt oder die andere wird erfüllt.
Negation, dafür nehmen wir den Not-Operator. Und es ist so,
dass eben durch die Klost-Wolt ist Sunption, es gegeben ist,
dass jedes, der Versuch etwas als wahr zu beweisen,
der fehlt, schlägt automatisch die Negation erzeugt.
Ja, es gilt dann als falsch. So variablend gelten generell
einfach nur innerhalb Der Klausel, wo sie definiert sind.
Also wir haben keine Blockstrukturen, nichts, wenn wir eine Klausel schreiben.
In dem Bereich ist die Variable gültig. Und wenn derselbe Name
irgendwo anders steht, ist es eine völlig andere Variable.
Und wir können auch nichts dagegen tun.
Und wenn sie einmal gebunden wurde, ist sie gebunden,
wir können sie nicht verändern. Ich weiß nicht,
ob ich das echt bis ich erwähnen wollen,
aber im Backtracking werden Variable belohnt, ja rückgängig zu machen.
Sie werden rückgängig gemacht, wenn sie in einer,
der Anwalt ist gut, während des Backtrackings werden,
Variablenbindungen rückgängig gemacht,
weil wir wieder zu Stufen
vorher zurückgehen
Aktivieren, eine der anderen Alternativen. Aber in jeder Variante
selbst bleiben sie immer gleich und wir verwerfen nur Teile,
die wir verfolgt haben, aber es ist nicht eine neue Wertzuweisung.
Es ist einfach beim Durchsuchen des Baumes, bauen wir verschiedene Welten
nebeneinander auf mit unterschiedlichen Variablen Bindungen und eine setzt sich durch.
Ja, darf nur einen geben. So. Ja,
anderer Teil, wo wir bei der Rekursion noch ein bisschen
darauf achten müssen,
In der Frühling-Programmierung zumindestens soweit, wie ich mich damit beschäftigt habe,
sind Listen genauso wichtig, wie sie für uns in Reckets sind.
Als Arbeitspferd, um Sachen da zu machen, singen wir ein bisschen anders aus.
Sie haben eckige Klammern, aber ansonsten ist es eigentlich das Gewohnte.
Und natürlich verwenden wir, um Listen zu durchsuchen, Rekursion.
Und als erste Übung machen wir mal das, was man immer macht.
Man versucht, eine Relation zu schreiben, die festzustellen,
versucht, ist denn ein Element, Element einer Liste?
Und dazu schreiben wir jetzt die Member-Relation. In Recket hätten wir geschrieben,
Eine Funktion Member kriegt ein Element, von dem wir wissen wollen,
ob es in der Liste ist und die Liste.
Und in Recket schreiben wir es als Relation,
da wird einfach geprüft, ist das Element,
was wir hier haben, steht es in der Beziehung,
es ist elementvoll mit der Liste hier hinten.
So, und um das auszudrücken, machen wir es rekursiv,
indem wir da die Fälle unterscheiden,
ist das Element gleich das erste Element in der Liste
Ist die Liste leer? Oder kommt es in der Restliste
vor? Die haben wir jetzt erstmal aufgeschrieben.
Es ist Element der Liste. Wenn es das erste Element
ist und dieser Punktoperator ist hier einfach das Cons.
In Prolock, in Reckett würde dann senkrecht der,
in Prolock würde senkrecht der Strich da stehen.
Und dann käme hier eine Variable für den Rest der Liste.
In Prolock, in Reckett habe ich da einfach unseren beliebten Punktoperator für genommen.
Also wir haben hier das erste Element und dann kommt eine Restliste.
Und dass ihr sagt, Wenn wir hier irgendeinen Rest haben
und das erste Element der Liste ist gleich dem,
dann ist es Element, es ist wahr,
brauchst gar nicht weiter zu suchen.
Zweite Variante, hier steht irgendwas, aber das ist nicht unser Item.
Aber wir haben einen Rest. Dann versuche zu beweisen,
dass dieses Element, Element vom Rest ist.
Und damit haben wir hier die Rekursion über die Liste beschrieben.
Das ist für die Lehrerliste falsch,
das brauchen wir gar nicht erst oft zu schreiben,
wir wollten mir keine Regel erwähnen für die Lehrerliste,
es ist automatisch gegeben
Also, wollen wir mal fragen. Kommt denn,
ist eins Element der Liste 2, 1, 3?
Vielleicht sollte ich noch erwähnen,
ein Pro-Log in Recket brauchen wir keine Quotierungszeichen mehr zu machen.
Durch die Quotierung, die wir vorhin gesehen haben,
mit den Zielen, ist sie implizit drin.
Okay, also, die Relation hier sagt, wenn wir,
deiner Fragen ist eins Element der Liste, yes.
Und wenn wir fragen, wenn wir nochmal fragen,
kriegen wir erstaunlicherweise die Antwort falsch.
Das heißt, es ist nicht Element,
hier ist nicht nur so ein bisschen Element,
sondern das heißt,
es kommt nicht zweimal vor
Für das erste Vorkommen kriegen wir ein Yes und alles andere
fragt, kommt denn in der Restliste ab?
Da ist noch vor und da ist es nicht.
Wenn zum Beispiel, wenn es zweimal vorkäme,
würden wir hier jetzt zweimal Jahr bekommen und dann einmal no.
Wir können aber auch fragen, ist,
wie sieht eine Liste aus, die eins als Element hat?
Und dann verwenden wir diese Anfragen als Konstruktor. Ja,
die haben sich vielleicht schon gefragt,
wie können wir überhaupt Listen konstruieren in pro Lok?
Es gibt keinen Konstruktor. Es gibt nur die Anfragen.
Und damit erzeugen wir Listen
Wir machen das einfach so, indem wir Klauseln hinschreiben.
Variablen werden gebunden und damit wird das Ding konstruiert.
Man gibt praktisch eine Schablone vor. Ja,
wenn ich so etwas hier frage, sage ich,
was mache ich da bloß mal mit der Maus?
Dann frage ich, wie sieht eine Liste aus,
die eins als Element hat und dreistellig ist. Ja,
eine Liste mit beliebigen drei Elementen sollen sie ABC heißen,
wie sieht die aus, wenn eins ein Element ist?
Und die erste Antwort, die ich kriege,
klar doch, eine solche Liste besteht darin,
dass A den Wert eins hat und B und C
haben irgendwelche Werte
Darf, wenn die fragt, na gut, interessant,
aber gibt es vielleicht noch eine andere Möglichkeit?
Gibt das Semikolern einen für die zweite Lösung? Dann erfahre
ich nimm irgendeinen Wert für A, setze B gleich einzeln in irgendeinen Wert für C.
Damit habe ich eine dreistellige Liste mit Element eins konstruiert.
Das ist ein bisschen faule Art, wie das in Prolog gemacht wird,
eigentlich für die vollständige Antwort müsste Prolog kennengehen und jetzt vollständig alle denkbaren Zahlen für A aufzählen,
um zu sagen, wie eine solche Liste aussieht,
oder die Antwort wäre dann etwas lang.
Also diese somarische Art ist sehr viel bequeme
Und das ist in Brüller genauso gelöst wie hier in meiner faulen Implementation.
Oder eben die dritte Variante, Sätze zählgleich,
1 und A und B können irgendwas sein.
Und diese drei Varianten werden genannt, auf die Frage hin,
bitte eine dreistellige Liste, die das Element 1 enthält.
So, also damit haben wir jetzt auch schon gesehen,
wie konstruieren von Strukturen in Prolog aussehen kann.
Und die zweite Art zu konstruieren,
also nicht das Vorgeben von Ausdrücken mit Variablen,
wo die Werte reingebunden werden,
besteht darin,
prädikate höhere Ordnung
Wir haben ja gesehen, in funktionalen Programmierstil ist das A
und O, wo es anfängt, Spaß zu machen.
Das sind die Funktionen, Hörer, Ordnung. Wenn wir
Funktionen als Werte konstruieren, wenn wir Funktionen als Argumente übergeben,
wenn wir Kontrollrahmen schreiben können, die wir mit Funktionen parametrisieren.
Und in Bruno haben wir die Prädikate zwar der Ordnung,
oh da, kann ich leider jetzt wirklich nur ganz kurz einen Blick drauf werfen,
weil sonst müsste ich hier ganzes Semester relationale Programmierung dranhängen.
Aber wir können eben auch Prädikate übergeben an Prädikate.
Und damit dann Ergebnisse zusammenfassen. Also wir übergeben Prädikatsaufrufe als Eingabewerte
. Und dann können wir auf diese Weise aggregierende Aussagen über
alle Fakten in der Datenbasis machen.
Dinge zählen und so weiter. Also ich habe in dieser
simplen Prolog in Record-Version jetzt nur ein einziges Prädikat höherer Ordnung drin.
Das ist das Find All, aber damit kann ich schon
ganz nett wie beim Find in Record nach allen Werten suchen,
die eine bestimmte Bedingung erfüllen und sie ihren Listen zusammenfassen.
Also wie arbeitet das Find All? Wir haben hier ein Ziel,
das beschreibt die Bedingungen an die Lösungen, die wir suchen.
Wir haben eine Liste, in der alles gesammelt wird,
was wir als Ergebnis zurückbekommen. Also da wird praktisch alles,
was beim Backtracking die Werte erfüllt,
genommen und zusammengesetzt und der Term sagt, gibt das Format vor,
in dem es aggregiert werden soll.
Das werden wir
gleich an einem Beispiel sehen
Und damit das funktioniert, müssen wir im Thermen- und Ziel
uninstanzierte Variable haben, nach denen gesucht wird.
Das Ziel beschreibt, suchen wir alle X, die das und das erfüllen.
Und der Therm sagt dann, in was für einer Liste
oder was für ein Ausdruck dieses X eingebunden werden soll,
um es zu beschreiben.
Und hier hinten haben wir dann eine Variable für die Liste aller gefundenen Ergebnisse.
Mal ein Beispiel, um es konkreter zu machen.
Wir suchen für eine Person
alle Vorfahren
Und dann würden wir sagen, suche, hier steht jetzt,
gucken wir hier nochmal auf den Term.
Das sind die Vorfahren, dass die, wir haben jetzt
einen sehr simplen Term, wir haben einfach Predicessor gesagt.
Hier ist das Ziel, das Bewiesen werden soll. Ja,
und unser Ziel, das bewiesen werden soll, ist,
wir suchen alle Bindungen an die Variable, vor Farid Predicessor,
die diese Relation erfüllen und sammle das Ganze in einer Liste Vorfahren.
Ja, ends ist das. Und wenn wir das mal
so aufrufen mit dem, diesen Find-All-Ausdruck,
dann erfahren wir hier praktisch alle Suche aus der Datenbasis.
Wer ist Vorfahre von irgendeiner Person? Oder suche alle Geschwister,
Find-All. Wir suchen mit unserem Geschwisterprädikat und kriegen dann alle Wertebindungen,
die Sippling von Walter hier diesen Ausdruck warm machen,
gesammelt in unserer Liste Sippling und haben hier unsere Liste mit den vier Ws.
Also das wäre ein Find-All. Also mit diesem kleinen Ausflug
im Prädikat, höherer Ordnung. Und wie konstruieren wir listen?
Schauen wir uns jetzt mal Knobelaufgaben an. Also wir benutzen
jetzt wirklich mal pro Log als Inferenzmaschine und geben dem Rätsel zu knacken,
die wir selbst auf den ersten Blick nicht wahrscheinlich lösen könnten,
sondern wo wir ein bisschen lange aus Papier starren würden,
Bleistift zerkauen und Alternativen ausprobieren.
Also jetzt brauchen wir pro Log zum Kombinieren.
Und einer der Klassiker, der in jedem Prülag-Buch steht,
ist das Zebra-Rätsel
Dann ist eines der wenig sinnvollen Rätsel, aber man hat ja lange zu knobeln,
das ist ursprünglich im Scientific American veröffentlicht worden.
Und das ist so diese typische Art, wo man sehr gut mit Backtracking was suchen kann. Also,
stammt aus einer Zeit, ist noch total gesellschaftlich akzeptabel,
war ungesund zu leben und man durfte rauchen und saufen und alles,
aber die Personen, die hier beschrieben werden,
sind jetzt verschiedene Nationalitäten und haben verschiedene Rauch- und Trinkgewohnheiten,
verschiedene Haustüre, verschiedene Haustiere, verschiedene Farben ihrer Häuser,
ja.
So, also fünf Häuser, fünf Bewohner,
jeder hat eine andere Nationalität, jeder ein anderes Haustier.
Jeder raucht was anderes, jeder trinkt was anderes.
Nichts raucher kommt übrigens nicht vor. Deshalb meinte ich,
es ist etwas älter, das Rätsel. So,
und die Frage, die jetzt beantwortet werden soll,
in welchem Haus wohnt der Wassertrinker?
Und wir hatten Zebra als Haustier, deshalb heißt es Zebra-Rätsel.
So, die haben wir ganz viele Regeln unterschiedlicher Art.
Und das ist eben das, was Poloc so stark macht.
Die Regeln betreffen alle unterschiedliche Domänen,
ja,
unterschiedliche Datentypen
Überhaupt alles unterschiedlich. Es ist sehr in Hunger gehen.
Wir können die Regeln einfach in unsere Pro-Log-Datenbasis reinschmeißen und die Suche
wird schon irgendwas damit machen. So, also die Regeln,
die Scientific American genannt hat für diese Situation, erstmal,
jedes Haus hat eine andere Farbe.
Ja, wir wissen, also, Haus 1 hat nicht
dieselbe Farbe wie Haus 2, Horst 3 und so weiter.
Jedes Haus, jeder hat eine andere Nationalität, es kommen keine zwei Briten vor.
Jeder ein anderes Lieblingsgetränk, jeder ein anderes Haustier,
jeder eine eigene Zigarettenmarke. So, und dann,
der Engländer lebt im Roten Haus, der Spanier hat einen Hund,
Im grünen Haus wird Kaffee getrunken, der Ukrainer trinkt Tee.
Und das grüne Haus ist direkt rechts neben dem Elfenbein farbenen Haus.
Regel 5. So, der Winstenraucher hält Schnecken im gelben Haus,
wird kurz geraucht. Im mittleren Haus wird Milch getrunken.
Norweger lebt im ersten Haus von links.
Also wirklich alles sehr unterschiedliche Regeln, ja.
Chesterfield Raucher ist ein direkter Nachbar vom Mann mit dem Fuchs
. Kuls Raucher, ein direkter Nachbar vom Pferdebesitzer.
Der Lucky Strike Raucher trinkt Orangensaft, Japaner raucht Paliaments,
Norweger wohnt neben dem blauen Haus
Ob sie es glauben oder nicht. All diese Regeln können wir mit dem,
was wir bisher für Polak besprochen haben, auch für Polak und Recket beschreiben.
Ja? So. Und die Frage ist jetzt eben,
unsere Frage war, in welchem Haus schringt man Wasser?
Und wer hat ein Zebra als Haustier? Sie haben
die Regeln gesehen, wissen Sie die Antwort schon?
Also ich finde es ganz praktisch, wenn man für sowas
eine Inferenzsprache nehmen kann und ich selber knurbeln muss.
So, damit wir genau für einen Fäuser haben,
reicht es jetzt dass wir die Häuserzeile als Liste mit genau fünf Elementen beschreiben.
Und jedes Haus selbst, die Attribute, die gefordert sind,
Nationalität, Haustür, Zigarettenmarke, Getränk, Hausfarbe.
Jetzt, wenn wir eine solche Struktur haben,
haben wir damit schon gesorgt, dafür gesorgt,
dass jedes Haus eins dieser Werte bekommen muss.
Dann Prädikate. Wie drücken wir aus, ob etwas benachbart ist?
Also da müssen wir uns die Konstrukturen für die Listen anschauen.
Wie arbeitet man mit Listen? Und unsere Instanzierungsvarianten für die Listen so vorgeben,
dass wir eben allgemeinen Listen beschreiben, bei denen zwei Variablen nebeneinander stehen.
Damit haben wir das Next-Tour ausgedrückt. Und beim Rechts von müsste die Variablen,
nach der wir fragen, von der sie rechts ist,
in einer Anfrage für eine Liste einfach rechts neben einer anderen Variable stehen.
Und damit ist sicher, dass in der Anfrage
die Teillisten so konstruiert werden, dass es erfüllt ist.
Also, wir wollen eine Prädikat beschreiben, das sagt,
Das Haus so und so ist rechts form.
Und das drücken wir oder ist benachbart zu.
Und das drücken wir aus davon, dass wir sagen,
okay, es ist entweder links davon oder rechts davon.
Wir definieren erstmal ein anderes Höchstprädikat, is right off,
is right off, ja.
Und dies ist rechts von zwei Variablen, links und rechts.
Entweder wenn unsere Liste mit Täusern genau damit beginnt,
zuerst kommt das Linke, dann kommt das Rechte und dann kommt irgendein Rest.
Oder aber, die Liste beginnt mit irgendeinem X und im Rest ist erfüllt,
dass die Variable Links von der Variablen rechts ist.
So. Und wenn wir das so definieren,
ist damit schon mal das Rechts von Ost gedrückt und benachbart.
Dazu können wir einfach sagen, es ist benachbart, X und Y,
wenn entweder X rechts von Y ist oder wenn Y rechts von X ist,
in der Liste X. Ja.
Also damit haben wir mit vier simplen Klauseln zwei Prädikate beschrieben,
die sagen, irgendwo in einer Liste gibt es zwei
benachbarte Werte oder das eine ist links von das andere rechts
Und jetzt können wir die ganzen einschränkenden Regeln in diesem Zipra-Rätsel aufzählen.
Würde helfen, wenn Sie jetzt das Skript vor der Nase
hätten und auf die Nummern der Regeln gucken können.
Aber wir können ja auch immer immer schnell einfach zurückblättern.
Also, Frage erstmal fürs Haus. Es gibt fünf Häuser,
Regeln wir dadurch, dass wir sagen, wir suchen eine
variable Haar für Haus und die ist gleich eine Liste mit diesen fünf Elementen.
Und hier stehen jetzt schon zwei Aussagen drin. Nämlich,
es gibt einen Norweger. Das war in der Regel zehn.
Es gibt ein Haus, in dem wird Milch getrunken.
Gucken wir nochmal, wo kommt das her?
1 und 11. Also Riegel 1 ist ja,
jeder der Besitzer, der hat einen eigenen Nationalität.
Das hätten wir da genutzt. Und vor allem jetzt
unser Norweger
Der Norweger lebt im ersten Haus von links, das war Regel 10. Genau.
So. Und das war noch was über Norweger gesagt worden.
Der Norweger wohnt neben dem blauen Haus.
So. Jetzt brauchen wir das Ganze also so auf.
Der Norweger wohnt im ersten Haus links. Das heißt,
wir erwähnen einfach dieses Haus mit den Norwegern und irgendwas anderem
als allererstes. Übers zweite Haus wissen wir gar nichts.
In der Mitte wohnt der Milchtrinker. Das ist diese Regel
. Wir haben es genau in der Mitte erwähnt für das
Haus konstruiert mit der Person, die Milch trinkt.
Über die anderen Häuser wissen wir erstmal auch nichts.
Diese Fragezeichen müssen gefüllt werden, indem wir die Member Relationen hier prüfen.
Ja, wir wissen, der Engländer wohnt in einem roten Haus.
Das heißt, es muss ein Element geben mit einem Haus,
mit einem Englischmen und das Haus ist rot.
Das wird eins dieser Fragezeichen hier füllen. Es muss ein
Haus geben mit einem Spanier, der einen Hund hat.
Es muss ein Haus geben, in dem Kaffee getrunken wird und das Haus ist grün.
Es muss ein Haus geben mit einem Ukrainer, der Tee trinkt.
Es muss ein Elfenbeinfarbenes Haus geben und das muss rechts sein vom Grünen Haus.
Das war die Regel sechs. Nehmen unsere Eireiterination.
Der Winstonraucher Halt Schnecken. Und dadurch,
dass wir hier sagen, so ein Haus muss vorkommen,
erzwingen wir, dass die fünf Häuser so genutzt werden.
Das Platz ist für den Günstenbraucher mit seinen Schnecken.
Dann haben wir, es muss hier einen Kulsraucher geben,
der ein gelbes Haus hat. Es muss einen Chest-Derfield Raucher
geben und daneben muss es jemand geben, der einen Fuchs hat.
Und neben dem Kulsraucher muss es jemanden mit einem Pferd als Haustier geben.
Dann haben wir noch den Lucky Strack. Raucher,
der trinkt Orangensaft. Das war die Regel 13. Ein Japaner
der Paljaminz raucht. Und dann haben wir Neben dir Norweger,
das wissen wir auch noch, das Haus ist blau.
Und die Anfrage war, wer hat ein Zebra und wer trinkt Wasser?
Die beiden Sachen haben wir noch gar nicht erwähnt,
damit überhaupt noch Zebra und Wassertrinker gefunden werden. Sagen wir,
es muss auch bei diesen fünf voll sein, eins davon,
muss ein Wassertrinker haben und eins davon muss ein Zebra sein.
Also all diese Member-Prädikate sind ja mit und verbunden implizit,
müssen alle erfüllt werden. Und dann ist die große Frage,
gibt es jetzt tatsächlich eine Lösung dafür,
wenn man das alles kombiniert und wie viele Lösungen gibt es
Ja, und wenn ich diese Anfrage jetzt stelle,
Zebra, wir wollen die Liste der Häuser haben,
wir wollen wissen, wer trinkt Wasser und wer besitzt das Zebra,
dann erfahre ich hier die Liste der Häuser,
das ist übrigens das, was ich hier gemalt habe,
Britte links im Gelben und so weiter.
Und hier werden sie, wird die Liste, die konstruiert wurde,
über all die Semember-Anfragen ausgegeben. Also das ist,
wie wir mit Listen in ProLog meistens typischerweise programmieren,
wir machen keinen Cons und so weiter,
wir schreiben einfach ein Listenmuster hin mit vielen,
vielen Variablen
Und nennen dann Bedingungen an die Art,
wie diese Varianten, ihr habt die gebunden werden,
sollten das Backtracken und die Unifikation konstruiert uns die Liste.
So, und dann haben wir hier unsere Antwort,
also der Wassertrinker ist der Norweger und der Zipra-Besitzer ist der Japaner.
Das haben wir also geschafft. Haben wir eigentlich noch Zeit?
Ja, Primeya. Kommen wir noch zwerpen Literaturkritik kommen. Also für einen Rätsel,
die vor Jahren mal den allerersten Band von Harry Potter gelesen hat,
da fiel mir auf, da gibt es ein Rätsel,
wo ich mir gedacht habe,
da hat noch die Joyne Rowling böse geschummelt.
Das Rätsel ist gar nicht lösbar mit den Angaben, die da drin sind.
Und ich habe gesagt, Mensch, wie kommt die?
Hören Mioni oder Hermine, wie sie in der deutschen Oscar
weist, darauf, dass das die Lösung ist.
Irgendwelche Angaben fehlen. Und ich habe dann die Regeln,
klar, ich hatte gerade meinen Prolog in Recket fertig,
wo ich die Regeln in Polog in Recket programmiert.
Und dieses Rätseln mit dem Gedicht einfach einmal einen Prolog übersetzt.
Und dann können wir uns angucken, ob es lösbar war oder nicht.
Also für diejenigen, die keine Harry Potter,
Leserinnen oder Leser sind, Das Buch endet im Wesentlichen,
damit das eine Höhle mit vielen, vielen Rätseln und Aufgaben da ist.
Und eins der Rätsel ist eine Logikaufgabe, die lebensgefährlich ist.
Jetzt stehen sieben Fläschchen. Und zwei von diesen Fläschchen enthalten einen Zaubertrank,
den man dringend braucht, um lebend da rauszukommen.
So, der eine Trank bringt einen dahin, wo man
eigentlich hin will, weil es was zu tun gibt.
Und der andere bringt einen wenigstens lebend und teilt zur anderen Seite
wieder zurück durch die Flammen, die um einen herum am Flackern sind.
Und in anderen Fläschchen ist dummerweise tödliches Gift oder auch einfach
nur ein Schlückchen Wein
So, das Gedicht, die Regeln, welches Fläschchen man nur trinken sollte,
die da so einladend stehen, ist als Gedicht beschrieben.
Danger lights before you volt safety lives behind, two of astral hard
pubice ever you will find. Vandemanga 7 will let you move a head,
also eine Flasche bringt einen sicher dahin,
wo man hin muss, tu einen Mann auch an,
numbers, another world transport the drinker back and stead,
auch nicht schlecht und nichts wie raus.
Two a mong our numbers hold only nettle wine,
3 of as a killers, waiting hitten in line.
Truth and this you wish to stay here for ever more
To help you in your choice, be give you
this clues 4. First, how ever slinly the poison
trice to high, you will always find someone nettle viness left side. Second,
different our door, sustand at either end,
but if you would move on work, nizer is your friend.
Third, as you see clearly all a different size,
night that wolf, no giant, holds death in their inside.
Force. The second left and second on the right,
are twins, once you taste them, so different at first side.
Ja, also was wir hier sehen, ist ganz ähnlich wie bei der Aufgabe
Mit der Zeile von Häusern und den Eigenschaften haben wir hier
eine Zeile von Fläschchen. Da habe ich gedacht, klar,
nehmen wir das alte Muster, was wir schon haben.
Das passt ganz gut. Und wir haben Regeln, die beschreiben,
welcher ist links, welcher ist rechts und so weiter.
Das Dumme ist nur, diese Regeln beschreiben auch die Größe
und Adwarf and Giant und all das.
Aber das hat die Joanne Rowling in dem Buch nicht beschrieben.
Es wird nirgendwo gesagt, welche der Flaschen in welcher Position
groß und klein ist. Das muss der Leser zusätzlich erraten.
Aber es ist wichtig, um das Rätsel zu lösen
Nee, ich weiß nicht. Nix. Die Angaben fehlen
völlig. Das ist eine ähnliche Schweinerei und unfair,
den Lesern gegenüber, wie das in den Shalak Holmes-Büchern war.
Also so außer Conan Joyle hat diese Methode eingeführt.
Da steht dann immer nur, hat das aus der
Conan Doll hat es wirklich auf die Spitze getrieben.
Da hat Shalak Holmes, der immer alles beobachtet hat,
ja, hat seinen Doktor Whatson an der Seite.
Und Dr. Wooxon hat ja den Bericht geschrieben,
aber der hat nie genau hingeguckt oder hat die Hälfte nicht mitgekriegt.
Und deshalb sind die Berichte mit den Fakten, die Dr. Wootzon weitergibt,
vollständig und die wichtigsten Sachen erfährt der Leser nie und man ist dann immer etwas überrascht und beleidigt,
wenn es am Ende rauskommt, ja,
das komische Stück Papier, was an Shadow Colmes aufgehoben hat,
das Dr. Wotson nur erwähnt,
das war der Zettel mit dem Fingerabdrück von Mörder oder so.
Das sind, also die wichtigsten Fakten verschweigt der Berichterstatter und
eine ähnliche Situation haben wir, meine ich hier.
Trotzdem mal gucken, was denn genannt sein sollte,
damit es listbar wird. So,
ich habe jetzt die Datenstrukturen für die kleinen Fläschchen da,
genauso gemacht, wie wir es von den Häusern her kennen.
Wir haben einfach den Namen der Flasche Inhalt, Gift,
Nessel, Wein und so weiter.
Dann haben wir die Reihe der sieben Flaschen als Liste mit
sieben Elementen und dann konstruieren wir es wieder über die Member-Relationen,
die erzwingen, dass bestimmte Elemente da reinkommen.
Also wir haben als erstes ja mal die Informationen, genau drei Giftflaschen.
Also für unsere Variabiliste Flaschen, da muss es geben,
ein Member, das Gift 1, das Gift 2,
das Gift 3,
drei tödliche Gifte und die kommen in den Flaschen vor
Dann haben wir den Netzelwein, davon gab es zwei,
das wissen wir. Und wir haben noch zwei Zaubertränke,
das sind die, die wir finden wollen.
Ein Trank, der einen sicher nach vorne weiterbringt zur nächsten
tödlichen Aufgabe, wo der Lord Voldemort wartet.
Ich weiß nicht, ob ich da wirklich hinwollte.
Und dann haben wir noch den Trank zurück, der einem
sich jetzt zurückbringt. Und damit ist dann schon garantiert,
wir kriegen in der Liste der sieben Flaschen genau diese sieben Dinge rein.
Dann haben wir noch eine Beziehung zwischen den Flaschen,
wo wir wissen, dass der Riese,
dass der auf keinen Fall Gift enthält und der Zwerg auch nicht.
Wir wissen aber nicht, welche Flaschen in welcher Position groß
und klein sind. Dummerweise. Wir wissen etwas darüber,
dass dem, von welchen Flaschen die Inhalte verschieden sind.
Wir wissen, welche Zwillinge sind im gleichen Inhalt enthalten und
dafür definiere ich hier verschiedene Zwillings, Prädikat.
Und dann wird noch gesagt, dass wir noch,
wir müssen noch abprüfen müssen,
ob etwas einen vorausbringt und dafür habe ich diese Regel
keinen Freund voraus bei gegebenem Inhalt
Jetzt können wir das Rätsel mit diesen Stützprädikaten etwas übersichtlicher schreiben.
Also erst mal, damit es genau sieben Flaschen sind,
sagen wir hier unsere Variable Flaschen, wo es diese Struktur haben.
Ja, 1, 2, 3 bis 7.
Dann haben wir die Regel mit den Giftflaschen eben erwähnt.
Nesselwandregel muss erfüllt sein, Tränke muss erfüllt sein,
damit wir hier die Inhalte darauf verteilt bekommen.
Denn hatten wir die Regel, Nesselwein steht links vom Gift
und das können wir hier so ausdrücken.
iRide, die Flasche mit Gift und Wein 1
und iRide Gift Wein
Die verschiedenen an den Enden, damit erzwingen wir,
dass diese beiden Flaschen verschiedenen Inhalt haben. Und wir wissen auch,
dass die erste und die siebte einem nicht vorausbringen.
Das war Zeile 2B. Zwei links, zwei rechts sind Zwillinge.
Damit können wir sagen, die sind gleich.
Ja, und dann gucken wir mal einen Probelauf.
Was kriegen wir als Lösung? Flasche 1, Gift,
Flasche 2, Gift, Flasche 3, Wein,
4 Gift, Trank voraus 6 und Trank voraus 7.
Das ist genau das
Die Lösung, die Herr Millione auch im Buch angibt,
ja. Aber ich habe da einfach mal gefragt,
gibt es zwei tolle Lösungen für das Ganze?
Und da erfahren wir dann, dass der Trank voraus hier
in der Mitte steht und gar nicht mehr am Ende, ja.
Und bei der Sechs hier, wo vorher Trank vorausstand,
haben wir jetzt mal einmal Wein stehen.
Und bei dem letzten, oh, ja, Trank zurück.
Da steht hier jetzt mit einmal das Gift. Also diese
Mehrdeutigkeiten, ganz haben wir das Problem noch nicht erfasst,
die sind wirklich lebensgefährlich
Wir müssen an irgendeiner Weise die Größen der Flaschen modellieren.
Nur Harry Potter und am Juni,
die stehen davor und die sehen die Flaschen,
die wissen, welches die Großen und Kleinen sind.
Ich kann jetzt nur Reverse Engineering machen und bei der Lösung,
die Herr Mooney gesagt hat, annehmen,
welches die Großen und die kleinen Flaschen sind und das Wissen hier reinstecken.
Und ich stecke jetzt aufgrund der Lösung,
die vorgegeben wurde rein,
Riese und Zwergs und die Flaschen F7 und F3
und wenn man die Fläschchen sehen kann,
dann bekommen wir hier diese
eine Lösung
Und das ist auch die einzige, weitere gibt es nicht. Ja,
also damit, wenn man die Flaschen sieht und weiß,
welches die Großen und Kleinen sind, dann ist es lösbar.
Ob er in der Ursprungsform ist es unfair,
ehrlich dem Leser gegenüber. Ja. Okay,
jetzt haben wir noch zehn Minuten, um zu zeigen,
wie man dann im relationalen Programmierstil funktional programmieren kann.
Den Weg zurück. Also jetzt machen wir was total Absurdes.
Wir haben eine relationale Programmiersprache in einer funktionalen Programmiersprache implementiert
und implementieren jetzt da drin,
den funktionalen Programmierstil
Okay. Also ich hoffe,
dass dann auch Kollege Menzel in seiner Vorlesung so weit geht,
dass er in der funktionalen Implementation, die er im Prolog gemacht hat,
die relationale Programmierung nochmal implementiert, aus Gerechtigkeitsgründen.
Gut, wofür brauchen wir funktionales Programmieren im Prolog?
Also eine der Gründe, wofür man es wirklich braucht,
ist die Arrithmetik. Mit den Relationen, die wir bisher haben,
können wir wunderbar natürlich über die pyanischen Aktionen,
die ganze Arrithmetik der natürlichen Zahlen aufbauen,
wenn man die erstmal hat,
kann man auch hingehen,
Rationalzahlen einbauen und so weiter und so weiter
Nur wenn man jede Addition über zwei Zahlen,
über eine Rekursion macht, bis zur Verankerung in den Piano-Aktionen,
das kann dauern und wird nicht gerade effizientes Rechnen geben.
Das heißt, wir wollen die Maschinen- und Operationen verwenden für die Arrathmetik.
Und deshalb bauen wir ein Schlupfloch ein in den funktionalen Programmierstil,
wo wir direkt Wertzuweisungen machen können und mit Zahlen arbeiten.
Und jetzt, also auf dieser Folie,
durchbrechen wir den reinen Prilant nationalen Programmierstil, Büßen,
alles ein dafür, was die relationalen Programmierstil mächtig macht,
zum Beispiel die Richtungsunabhängigkeit.
Genauso, also es ist wirklich das essentieller Punkt,
wenn wir in funktionalen Programmierstil anfangen, imperativ zu programmieren,
was verlieren wir dann als wichtigste Eigenschaft?
Benedikt? Benedikt. Genau, da verlieren wir
die Bezugstransparenz, ja. Also jedes Durchbrechen des Programmierstils kostet
Einer funktionalen Programmiersprache müssen es wirklich sehr, sehr wohl überlegt machen,
wenn wir anfangen, imperative Elemente zu verwenden.
Das kostet uns die Bezugstransparenz. Im relationalen Programmierstil,
in dem Moment, wo wir anfangen,
das zu tun, was ich hier jetzt beschreibe,
da kostet es uns die richtungsunabhängigkeit und wir können mit einmal Anfragen nur noch in eine Richtung machen.
Und es klappt nur noch für bestimmte Instanzierungsvarianten. Gut,
aber trotzdem, man braucht es,
müssen wir einen sauren Apfel beißen und schauen uns mal an,
wie es gehen kann, wenn wir tatsächlich schlichtweg verschiedenen Additionen nehmen wollen,
statt Rekursionen über Piano.
Gut, und dieses Schlupfloch ist der Ist-Operator.
Mit dem können wir gezielt in bestimmten Stellen sagen,
Variable so und so hat den und den Wert.
Und dann, um diesen Wert zu ermitteln,
schreiben wir einen funktionalen Ostdruck hin und der rechnet uns schlichtweg in Recket aus,
was der Wert sein soll und bindet ihn an die Variable.
Und wir können auch Werte direkt vergleichen mit dem Testoperator und
die Unifikation ist erfolgreich,
wenn diese Tests gut gehen
So, aber bevor wir das tun,
müssen wir unserer sicher sein,
dass wir die Anfragen so gestaltet haben,
dass wenn wir auf dieses Ist- und Test treffen,
dass alle Variablen durch Unifikation schon an Werte gebunden sind.
Wir können nicht undefinierte Variable addieren oder sowas.
Mal ein Beispiel. Wir wollen wissen, wie viel ist
2 plus 4 und das soll richtig gerechnet werden.
Können wir im relationalen Programmierstil so schreiben?
Wir haben eine Anfrage. Hier das Schlüpfloch,
wo wir schlichtweg Recket aufrufen
Und da wird gesagt, rechne mir bitte diesen Record-Ausdruck aus,
2 plus 4 und binde ihn an die Variable X.
Das ist das, was hier steht.
Ja, und dann erfahren wir XS6. Ja? Und wir wollen wissen,
ist X-größer Y, wenn X und Y bestimmte Werte haben.
Wir binden hier XN-3, binden hier Y an 5 und
führen dann den Test aus, ist Y größer X. Ja?
Also dies hier sind alles Record-Ausdrücke. Und auf diese Weise
können wir in jedes Prolog in Record-Programm beliebige Unterprogramme in Record geschrieben aufrufen.
Wir müssen nur ein Ist haben, das uns den Wert
Das heißt, die beiden Sprachen leben dann unter nebeneinander.
Aber wir können jetzt nicht fragen hier,
ist sechs zum Beispiel hier vorgeben und fragen,
welches X plus vier ergibt sechs?
Ja, das geht schief. Aber wenn wir jetzt Mapping-Funktionen,
Funktionen höhere Ordnung haben wollen und so weiter, gar kein Problem.
Wir können hier einfach hingehen und hier unser altbekannten Recket-Ausdrücke hinschreiben,
ein Map von Ed über irgendwie eine Liste und so weiter.
Und wir kriegen oft diese Weise
die Funktionen höherer Ordnungsresultate in Brulock gegeben,
Wir können jetzt auch mal anfangen, rekursive Relationen zu schreiben,
um die Länge einer Liste zu erstellen.
Können wir das noch? Ja, fünf Minuten haben wir
noch. Also wir wollen die Länge einer Liste feststellen.
Und da können wir natürlich zuerst sagen, wenn unsere Liste hier leer ist,
hat sie die Länge null. Also längst ist jetzt keine Funktion,
sondern es ist eine Relation, die uns sagt,
die leere Liste steht in der längen Relation mit dem Wert null zum Wert null.
Und wenn unsere Liste aus einem ersten Element und einem Rest besteht,
und irgendeine Länge hat, dann können wir die genaue Länge erfahren,
indem wir die Länge des Restes ermitteln, ja, Länge des Restes.
Hier wird sie gebunden, so. Und wenn wir
die Länge des Restes kennen, wenn die gebunden ist,
dann können wir hier unten im funktionalen Programmierstil hingehen,
die Schlüpfloch ausnutzen und eins dazu addieren und dann die Länge einer Liste mit irgendeinem X davor berechnen.
Also hier ist die Reihenfolge essentiell, dass das ist,
erst nach der Stelle kommt,
wo wir tatsächlich die Länge schon gebunden haben.
Und das können wir testen, klappt für die Länge
der Liste ABC,
kriegen wir hier drei raus
So, okay. Ja, dies wird unser großes nächstes
Thema. Ich glaube, bei der Link ist gebrochen,
was auch gut ist, weil wir wollen ja ohne Hinschluss machen.
Ich werde das nächste Mal noch ein paar Tricks und Kniffe
für selbst modifizierenden Code vorstellen und so die Dinge,
wo es sich wirklich lohnt,
dass wir das Ganze in Reckett machen und nicht in Häskel oder in diesen strengen,
typisierten Programmiersprachen.
Ich werde auch noch ein, wenn die Zeit bleibt,
eine weitere Fallstudie vorstellen und
den letzten Termin möchte ich dann kommen
Plett dafür reservieren,
dass wir eine Wiederholung machen und zusammenfassen den Stoff nochmal durchgehen und
vielleicht auch nochmal die Fragen zur Prüfungsvorbereitung und so durchgehen,
damit wir sehen,
wofür sie dann mit Dienstag danach fit sein sollten.
Danke für die Aufmerksamkeit