In die relationale Programmierung einsteigen, dass es so verzerrt dargestellt wird,
ist nicht meine Absicht und auch keine Kritik im Frühlock oder im Frühlock ähnlichen Sprachen,
das irgendwie kriegen wir den mit dem Lecture to go,
dem Wieman nicht gebändigt.
Mal gucken, ob das so gehen wird.
Also was sich Hot Gun mit Ihnen durchsprechen möchte,
ist überhaupt erstmal den Übergang vom funktionalen Programmieren zum relationalen Programmieren,
um zu sehen, wo sich die Verarbeitungsmodelle grundsätzlich unterscheiden.
Und ich möchte diese Gelegenheit benutzen, Wenn ich schreibe,
wie es im relationalen Programmieren ist, zurückzuerinnern,
wie das entsprechende Teil im relationalen, im Funktionalen oder im Imperativen aussagt.
Also wir werden heute mit ProLog beginnen,
überhaupt erstmal die grundsätzliche Idee einer logischen Programmiersprache,
die auf Relationen aufbaut, kennenlernen und dann hoffentlich so weit kommen,
dass wir auch ein paar interessante Beispiele damit behandeln können.
In der ersten Ansatz kann man proLog verwenden,
für jede Art von relationaler Datenbank,
die man
gern bauen möchte
Wir schauen uns also zuerst an, wie wir damit Datenbanken
bauen können, indem man intelligent und schnell suchen kann.
Und dann das, was mir eigentlich viel mehr Spaß bringt,
den Teil, wo wir pro Log als Inferenzmaschine benutzen,
die logisch Schluss folgern kann und für uns Rätsel lösen kann.
Dafür habe ich zwei Beispiele vorbereitet. Gucken wir mal,
wie weit wir da mitkommen. Das Aufgabenblatt,
was heute verteilt wurde und in Stine steht,
enthält einen Teil von Übungsaufgaben zu Pro Log,
wie sie eins zu eins in der Klausur vorkommen könnten.
Das sind also Beispiele aus einer früheren Klausur
Mit ähnlichen Aufgaben müssten sie auch an den beiden Klausuren rechnen. Gut,
was beim relationalen Programmierstil wichtig ist, ist,
dass wir uns zunächst mal überlegen, was bedeutet es überhaupt,
wenn wir Relation oder die Sprache der Mathematik und Logik und Logik kaltkühl als Programmiersprache nehmen.
Und dann, wie machen wir daraus eine Programmiersprache?
Und im Wesentlichen werden wir sehen, dass wir wieder den Weg gehen,
den wir angefangen haben mit dem Beispiel Eliza.
Alles, was an Beziehungen über die Objekte in unserer Welt
wichtig ist, schreiben wir in Form von Regeln in einer Datenbasis
Der kleine Kontrollrahmen, den wir haben,
der wird dafür sorgen, dass in dieser Menge an Fakten,
die wir zugesichert haben, eine mögliche Lösung gefunden wird.
Und dafür sind die wichtigen Bausteine,
die wir fertig kaufen mit jedem Pro-Log-System, Unifikationenssuche,
Unifikationen schauen wir uns gleich richtig an, ist eine Art Pattern-Matching,
die Anfragen mit der Datenbank vergleicht, Variablen bindet.
Und das ist für uns das einzige Ausdrucksmittel in dieser Programmiersprache.
Indem wir, muss ich da vorgeben,
Variablenbindungen erzeugen und dann in diesen Variablenbindungen
das Resultat erfahren
Die Suche ist auch fest vorgegeben, wir können sie parametrisieren,
aber nicht in dieser Billig-Variante, die ich hier implementiert habe.
Genau. Also Grundidee, das hatten wir ja in der
allerersten Vorlesung schon gesehen, das Verarbeitungsmodell relational.
Rennen damit sofort, was ist das Verarbeitungsmodell,
das ist unsere Vorstellung davon, was der Rechner kann,
den wir nutzen, um unsere Probleme damit zu lösen.
So, und wir hatten gesehen, wir haben das Imperative Verarbeitungsmodell,
da gehen wir davon aus,
dass wir dem Rechner Anweisungen geben können,
er führt die Anweisungen aus und dann ändert sich der Zustand der Berechnung und Das Resultat ist eben,
dass sich dein Zustand geändert hat.
Das war rein imperativ. Wir hatten das Verarbeitungsmodell funktional.
Da ist unsere Sicht, dass der Rechner Funktionen kennt.
Und wir komponieren funktionale Ausdrücke. Die werden angewendet auf Werte.
Und das Resultat der Berechnung ist der Wert, der zurückkommt.
Und beim relationalen Programmier stillt er, sichern wir Beziehungen zwischen Objekten zu.
Haben eine Datenweise. Haben Sie die Auflösung nochmal geändert?
Ich hatte sie auf... Ich habe kein Signal mehr,
der Splitter eigentlich nicht. Aha, gut. Gehen wir nochmal zurück.
Ich hatte die Hoffnung, dass es weniger verzerrt wird.
Das ist so klein wie möglich, kann. Und jetzt,
ich glaube, 1024, 30 Jahre, 60 Jahre optimal.
Dann nehmen wir 720. Ja, das probieren wir dir mal.
Ja. Gut. Dann noch einmal so. Beim relationalen Verarbeitungsmodell
sammeln wir einfach an Fakten, was wir zu fassen kriegen.
Wo werfen diesen Wust an Fakten dem Rechner vor und fragen ihn
dann was und der versucht, logisch zu kombinieren und zu sagen,
ja, unter der Bedingung das oder nein.
Und ein Fakt könnte zum Beispiel sein,
dass wir zusichern, der Mörder ist immer der Gärtner.
Wir haben eine Relation Mörder und irgendein Objekt.
X steht als ermordete in Beziehung zu einem Mörder und als Mörder
haben wir vier Fest vorgegeben, das ist immer der Gärtner.
Wenn wir jetzt in dieser Datenbasis, in diesem Prolog-Programm herauskriegen wollen,
wer hat Paul ermordet? Stellen wir eine Anfrage. Und
die Anfrage ist, wir fragen, das Opfer ist Paul.
Welche Variable M steht in der Mörderrelation zu Paul?
Und Prolog wird seine Datenbank durchsuchen und sagen, M ist Gärtner.
Ja, und wenn wir jetzt in Semikoland eingeben,
eine Frage, gibt es zwei, drei Mörder,
war das vielleicht eine Gang, dann erfahren wir no.
Und Anno in dieser Welt heißt Closed World Assumption, geschlossene Welt.
Das heißt nur, ich kenne keine weiteren Mörder,
das heißt, Keine weiteren, ja.
Aber in der Welt, die Polo kennt,
heißt es No, sonst ist es bekannt. Ja,
das ist die Art, wie wir im Prolock programmieren werden,
einfach eine Datenbasis von Relationen mit Variablen und den Zustand der
Berechnung erfahren wir als Wertbindung für diese Variablen.
Und das, was diese Wertbindung herstellt, ist eben der Unifikationsalgorithmus.
Verbindung mit der Suche. Also ich greife immer dann zum
logischen Verarbeitungsmodell oder relationalen Westbärennamen, sind synonym.
Wenn ich etwas lösen muss, über Beziehungen zwischen Objekten und
die Typen dieser Beziehungen können vielfältig sein.
Ich möchte frei sein, irgendwelche Relationen auszudrücken, die einfach einzuführen,
ohne große Typdeklarationen über die Art der Beziehung und so weiter.
Also wenn wir einfach Fakten sammeln und wollen diesen Fakten was entdecken,
ja, oder wenn wir automatisch etwas beweisen wollen,
basierend auf dem, was wir schon wissen.
Und dieses Verarbeitungsmodell ist deklarativ, eigentlich ganz genauso wie das Funktionale,
was wir kennen. In der funktionalen Welt haben wir das
Landerkalkül, um die Semantik und die Bedeutung unserer Ausdrücke
zu beschreiben
Und im relationalen Programmierstil haben wir Relationen an der Mathematik wohl etabliert und Logik,
auch seit Jahrhunderten oder sogar Jahrtausenden wohl etabliert, mit dem wir diese Mantik beschreiben können.
Also für Logikprogramme in pro Lockart ist es folgendes ganz charakteristisch.
Also wir haben erstmal eine sehr einheitliche Uniforme Datenbasis, ja.
Das ist eigentlich das Einzige, was wir schreiben müssen,
möglichst gut kommentiert, aber wir schreiben in eine Datenbasis,
sichern wir Fakten zu, ja,
Fakten und Regeln als Klauseln und Klausel, das,
was bei Rackett, ein funktionaler Ausdruck wäre,
im funktionalen Programmierstil ist ein Prolog eben die Klausel.
Wir haben logische Variable. Auch da gilt die Bezugstransparenz,
wer sie aus dem funktionalen Programmieren kennen.
Eine Variable im Prolog wird grundsätzlich nur einmal gebunden.
Ja, also da sind wir jetzt endgültig davon weg,
dass wir den Wert einer Variable während der Berechnung ändern können.
Es gibt da kein Set Bang mehr, sondern in dem Moment,
wo eine Variable eingeführt haben und die Bindung wird hergeführt,
bleibt der Wert erhalten für die Dauer der Abarbeitung dieser Klausel
Das Backtracking, wenn gesucht wird, müssen wir nicht selbst programmieren.
Das ist fest da. Also da kümmern wir uns gar
nicht weiter drum. Was besonders spannend ist, ist,
dass wir viel Zweckprogramme haben. Wenn wir diese Datenbasis haben,
können wir damit viele Programme ablaufen lassen, je nachdem,
wie wir fragen. Wir können fragen, wer hat Paul
ermordet oder wir können fragen, wen hat der Gärten?
Wen hat der Gärtner ermordet oder wie viele Mörder gibt es?
Wir können in vielen Richtungen diesen Datenbestand und Faktenbestand und Regelbestand
durchsuchen.
Und die Relation, die wir definieren, die sind gleichzeitig
unsere Konstrukturen für Datenstrukturen. Und sie sind die Akzessoren.
Also wir müssen da nie eine Datenstruktur deklarieren.
Wir benutzen sie einfach. Und indem wir Variable einsetzen,
sagen wir, ich möchte den und den Wert erfahren.
Das Hinschreiben einer Klausel gibt uns gleichzeitig den Konstrukt dafür Daten
und für den Zugriff auf die Komponenten
Gut, in diesem Kapitel wollen wir erstmal
mit all diesen wesentlichen Eigenschaften vertraut machen und sehen,
wo sie uns beim Programmieren helfen können.
Und dann gucken wir uns so ein paar typische Programmierprobleme an,
an denen man sehen kann, wo es nützlich sein könnte.
Und dann gucken wir uns auch noch an,
wie man das Ganze implementieren könnte.
Das ist wahrscheinlich nicht mehr heute, sondern das nächste Mal.
Jedenfalls habe ich dieses Pro-Log nach einer Vorlage,
die ist im Kommenlist von Peter Norweg geschrieben wurde,
In Reckett und ihn als Pro-Log in Recke zur Verfügung gestellt.
Das können sie also gerne benutzen. Also das Wichtigste,
was wir als erstes mal hinkriegen müssen, ist,
dass wir eine Datenbasis mit Fakten haben und mit Regeln,
wie diese Fakten kombiniert werden können.
Also und dieses, das,
was in diese Datenbasis kommt, nennt sich Klausel.
Das ist das grundlegende Element eines Pro-Log-Programms ist die Klausel.
Und davon haben wir zwei Arten. Das eine sind einfach Fakten,
wo wir eben zu sichern, wer ist der Mörder oder so.
Und das andere ist das,
was noch mehr Spaß bringt,
das sind die Regeln
Also bei Fakten könnte es stehen,
das Krasse ist grün oder wir haben Winter, ja.
Bei den Regeln steht, wenn Winter ist, kann es schneien, ja.
Also da werden Vorbedingungen genannt und was daraus abgeleitet werden kann.
Ja. Hab ich das nicht verstanden? Das ist ja
nur so ein Frakzeug, das ich zum Beispiel wahre,
spricht Millionär, spricht C und entwickelt mir dann,
wenn Adel gleich B ist und wird jetzt erst mal so AFC.
Genau, aber genau das Wissen brauchen wir nicht zu modellieren,
das ist schon fertig drin, aber zum Beispiel,
wenn der Preis von einem Produkt höher als 100 ist,
ist es teuer oder sowas,
Und wie werden wir diese Fakten und ja, überhaupt die Klauseln realisieren?
Na klar, wir sind in einer lisp-ähnlichen Programmiersprache,
der schreibt mir das Ganze einfach als Listen hin.
In Listennotationen, das macht es uns am einfachsten,
das in Recket einzubetten. Also wir würden schreiben,
eine Relation über die Bevölkerung, ja, würden wir so schreiben,
dass wir Klammer aufmachen, den Namen der Relation nennen,
dann sagen, welche Stadt es ist und dann welche,
die,
wie viele Leute da leben oder eine Relation Hauptstadt,
Hauptstadt von Kalifornien ist sakramente. Ja, also das wären jetzt Fakten,
ausgedrückt durch eine Relation Population und durch eine Relation Capital.
Und das schreiben wir einfach in dieser Art hin,
Klammer auf, nahmen wir der Relation und dann dippen Elemente aus
der Basismenge über diese, die diese Relation gebildet wird.
Und das kann man im simpelsten Fall erstmal einfach erschöpfend aufzählen.
Also diese Form ist, wie wir es in Recket in
Prolog machen. Und diese Formen ist es,
wie es in echten Prolog geschrieben wurde,
im richtigen Prolog würden wir schreiben, Population,
dann die Klammer auf und dann hier noch einen Komma reinmachen
und Klammer zu und am Ende auch noch
einen Punkt
Das Komma und der Punkt und so weiter,
die machen uns ziemlichen Ärger in Reckett,
plus wenn die Klammern nicht vor dem Relationsnamen steht,
also deshalb, wir schreiben es hier so.
Diejenigen von Ihnen, die jetzt in diesem Semester ziemlich viel im Polock programmiert haben,
denen möchte ich anbieten, dass Sie alle Prü-Lock-Fragen in der Klausur,
die wir schreiben, mit dem richtigen Prolock beantworten.
Wenn Sie auf dem Klausurbogen obendrauf schreiben,
wenn eine Aufgabe zu Prolock kommt, verwendete Syntags pro Lock,
Ja, dann können sie eben gerne das in dem Prolog,
was hier das ganze Semester geübt haben, beantworten.
Wir müssen nur wissen, auf was sie sich festlegen.
Also was nicht geht, ist bei den Aufgaben immer hin
und her schwanken, je nachdem, was ihnen gerade einfällt.
Legen sich zu Anfang fest, welche Sprache sie verwenden,
wo ihnen wollen. Aber die Aufgaben selbst werden so gestellt werden,
dass sie lesen können müssen, Klammeraufnahme der Relation und dann die Elemente des Tuppels der Relation.
Ja. Gut. Fangen wir mal an mit einem Beispiel,
dass ich mir bei, weiß gar nicht, Menzel ausgebucht habe,
Das Like, ja, oder gern haben oder mögen. Also wir können,
wenn wir jetzt für unser Social Network eine Relation beschreiben wollen,
wer hat für wen den Like-Button gedrückt,
dann können wir zum Beispiel aufzählen, Kim, Likes,
Robin, oder Sandy Lee und Sandy Kim und so weiter,
beziehen einfach auf in der Likes-Relation Kim Robins, Sandy Lee,
Sandy Kim, Robin,
Mark Katzen.
Ja. Ich habe sie okchistisch nicht verstanden.
Wieso habe ich nichts mehr gemacht, aber die Direktion zwischen
den beiden ist nicht bindirekt
In dem Fall ist es Unidirektional. Ich habe hier noch kein Prädikatschema
drüber gesetzt. Also hier ist Kim, die Person,
die mag, und das ist das, was gemockt wird.
So, Kim bleibt Robin Sandy likesly und so weiter.
Ja, so wie es hier oben steht. Also you
open sandy mugly inskim, ne? Die Frage ist aber gut,
also das Erste, woran wir uns gewöhnen müssen,
wenn wir Relation schreiben, ist erstmal ein Prädikatschema drüber schreibt,
ein Kommentar, der sagt,
was die Bedeutung der Reihenfolge der Komponenten ist
Ja, sichern wir so eine, solche Tupel einer Relation in der Datenbasis zu.
Dafür implementieren wir in Pro-Log den Special Form Operate, Special Form Operate Assert.
Ja. Und das implementieren wir als ein Makro schauen wir
aus der nächsten Vorlesung an, wie man das mit Makros macht.
Heute gehen wir einfach davon aus,
dass wir mit Dev Makro ein neues Special Form einführen können
und diese Special Form dann sind taktisch anders ausgewertet wird,
als das, was wir bisher in Prolock haben.
Um unser Prolock zu realisieren, müssen wir
genau zwei Special Forms einführen und damit haben wir das.
Also das eine ist dieses Assert, das Eintragen in der Datenbasis.
Also dieses Sird-Makro, dem geben wir diesen Namen.
Und dem sagen wir einfach, was es eintragen soll,
Like Kim Robin oder Like, Sandy Lee und so weiter.
Ja? Und wenn wir, kommen wir kurz zurückbesinnen,
wie würden wir das in Racket machen?
Dieses mögen es ja eine zweiseitige Sache. Also wenn wir
das hier hinschreiben, dass Kim Robin mag, ja,
dann können wir in Prolog nachfragen, wer mag Robin oder wen mag Kim.
Wir können es in zwei Richtungen verwenden. Das geht in
Recket nicht. Da müssten wir zwei Funktionen schreiben.
Wir müssten eine Funktion schreiben, die zusichert. Likes,
da können wir fragen, wer mag denn die Sandy und würden eine Listilly und Kim zurückkriegen?
Und in dem Moment Also für uns,
das hier ist jetzt diese Richtung, wo wir fragen,
was mag Sandy und Sandy Marcley und Kim?
So, und wir können jetzt, müssten für die Gegenrichtung,
wer mag denn Lee? Fragen, eine andere Funktion,
Leicas Off, ja? Also in Reckett müssten wir
zwei Funktionen schreiben, um diese Funktionen auszuwerten in beide Richtungen.
In Prolog schreiben wir es nur einmal hin und wir können
in beide Richtungen dann suchen. Ja,
wir haben also die Richtungsunabhängigkeit und was man im Prolog typischerweise macht,
ist einfach Anfragen mit Variablen stellen,
hatte ich schon beim Anfangsbeispiel mit dem Mörder und Gärtner gefragt, ja?
Wenn wir fragen, Die Anfrage stellen Likes, Sandy,
Whoom, dann fragen wir, dieses Objekt Sandy,
mit welchen Werten steht, wird die Relation wahr, Likes, ja?
Like Sandy. Und das wird eben wahr,
wenn wir an die Variable den Wert lieben oder wenn wir
an die Variable Huhenden Wert kämen binden.
Und das Resultat einer Berechnung in Pro-Log ist, dass wir
die möglichen Variablen Bindungen erfahren, eins nach dem anderen, ja?
Wir kriegen zuerst eine mögliche, dann fragen wir nochmal,
wenn wir sie mit Kudern angeben,
kriegen wir die zweite und so weiter.
Wir können in die Gegenrichtung fragen
Wo wir fragen, wer mag denn lieb? Und da
würden wir dann erfahren, huch, Sandy, ja?
So, diese beiden Arten, die Variablen an verschiedene Stellen
in die Anfrage zu setzen.
Oder überhaupt in einem Ausdruck. Die nennt sich Instanzierierungsvariante.
Instanzierungsvariante, ja? Die Relation hier ist nicht vollständig instanziert.
Wir haben da nur an einer Stelle Einen festen Wert und in der zweiten
eine Variable und die Variablen könnten an verschiedenen Stellen auftauchen.
Und je nachdem, wo die Variablen stehen, fragen wir noch unterschiedlichen Sachen.
So, das war also die eine Art.
Das waren einfach Fakten, die wir zusichern.
Und jetzt können wir noch Dinge zusichern, die sagen,
was aus wem folgt. Und das sind dann Regeln.
Und eine der Regeln ist zum Beispiel, wenn wir sagen wollen,
Sandy mag jeden, der Katzen mag.
Was ist der Unterschied in der Mächtigkeit? Also wenn wir einfach
nur Tuppel aufzählen, dann können wir logischerweise in einem Programm nur endlich viel zusichern.
Irgendwann geht uns die Geduld aus und wir haben entweder keinen
Speicherplatz mehr oder keine Zeit mehr noch weitere Fakten reinzuschreiben.
Wenn wir Aussagen über unendliche Domänen machen wollen oder potenziell unendliche,
ist es einfacher, man macht es kompakt durch Schlussfolgerungsregeln.
Und dafür sind eben die Regeln da.
Hier können wir Folgendes zusichern. Sandy steht in der Relation
zu jedem
Das Sandy, dieses X-Mark, ja, like Sandy X,
was immer das X ist, Sandy Markes,
wenn diese Vorbedingung erfüllt ist, dass dieses X Ätzen mag.
Also, wir haben an der Stelle gesagt, Sandy mag
jeden Katzenliebhaber. Ja? Mhm. Was eigentlich passiert,
wenn ich sagen würde, jeder, der stogen,
was mag, der mag auf Sandy.
Jeder, der irgendwas mag, also da würden wir
zwei Variablen XY reinsetzen und das geht.
Wir würden da eine ziemlich große Antwortmenge kriegen, ne?
Ich wollte gerade sagen,
nur das exklusiv
Ja, ja. Ich mag Sandy, weil ich mag,
weil irgendwer Sandy ist, also mag ich irgendwer.
Das Anwenden der Regeln, das geschieht durch Backdrecking und das wird
mit Baumrekursionen durchsucht. Und das ist auch eines der Punkte,
wo man ein bisschen aufpassen muss in der Prolo-Kriege,
Programmierung, in welcher Reihenfolge man die Sachen nennt,
damit man möglichst keine Endlosrekursionen bekommt.
Ja? Also wir können die unendliche Relation definieren,
ja, über unendliche Domänen und mit einem endlichen Programm,
das nur endlich viel Text hat
Also diese Regel, die wir hier auch geschrieben haben,
die können wir in zwei Arten interpretieren.
Also das Deklarative ist es erst mal aus der Seite
der Semantik der Programmiersprache, haben wir hier zugesichert.
Für alle X gilt Sandy Mark X, wenn X Katzen mag.
Und für Prolog als Programmiersprache bedeutet es jetzt in der Operationalen Semantik,
das heißt, wenn du rauskriegen möchtest,
Ob Cendi jemanden mag oder beweisen willst,
dass jemand jemanden mag, ja.
Dann versucht zu zeigen, zu beweisen,
dass dieser jemand Katzen mag, ja. Also,
stellen wir uns vor, wir haben die Anfrage gestellt,
ja, wen oder was mag Cendi denn?
Und dann suchen wir oder sucht pro Lock in der Datenbasis
nach allem, wo irgendwie ein Likes vorkommt und Sandy.
Und dann kommen die auf die Stelle, oh la la.
Wenn Sandy, wenn jemand Katzen mag, dann mag Sandy Die sind jemand, ja.
Also es heißt, wenn jetzt gesucht wird, operational,
versuche zu beweisen, dass dieser jemand Katzen mag.
Versuche also einen X zu finden, was dem Rechten,
die rechte Seite der Regel wahrmacht, ja.
Versuche eine Wertbindung für X zu finden, die auf der,
wie die rechte Seite wahrmacht. Und wenn ich jetzt den Verdacht habe,
dass Peter Katzen mag, ja, aber ich finde keine,
keinen Hinweis oder keine feste Regel, die sagt,
ob Peter Katzen mag oder nicht,
versuche ich eben aufgrund anderer Regeln zu beweisen,
was Peter denn mag
Und da kommt die Rekursion ins Spiel. Nochmal, zwei
komplexer Fragen. Da kann es nicht sein. Erstmal fragen wir,
kann ich auch sagen, es ist ja wie magiert,
wenn keine Katzen macht. Das ist,
man kann es, ja, gibt dir Negation,
aber die Negation ist recht schwierig in der Pro-Log-Welt,
weil wir da von einer geschlossenen Welt ausgehen.
Also das würde genau dazu führen, dass wir sagen,
jemand mag keine Katzen, wenn wir keinen Fakt,
wenn wir überhaupt kein Faktum haben, dass Aussagen drüber macht,
über Katzen mag oder nicht,
dann würde nicht rauskommen,
Das ist, also die Negation ist Nicotion bei Fehler,
also wenn ich nicht, wenn ich nicht beweisen kann,
dass etwas wahr ist, nimmt Pro-Log an, dass es falsch ist.
Genau, die machen es eben,
weil ich da eine Definition zeige, die ich sage,
jeder, der keine Katzen mag, mein Sandy.
Jeder, der Sandy mag, macht keinen. Ja,
kommt drauf an, in welcher Reihenfolge es abgearbeitet wird.
Es kann sein, dass das Programm sehr lange läuft.
Oder gar nicht, ne? Also, guck nochmal,
das, was wir hier gesehen haben,
Wenn wir zeigen wollen, ob jemand Katzen mag oder nicht,
ja, das ist eben die Rückwärtsverkettung oder Backward-Chaining, ja.
Das ist die operationale Interpretation, eine operationale Semantik von Prolock. Versuche,
etwas wahrzumachen, indem man nach rechts nach Vorbedingungen sucht,
die es möglich machen und dann versuche zu beweisen,
dass diese Vorbedingungen gelten. Man geht rückwärts immer weiter,
bis irgendeine der Vorbedingungen, die man gefunden hat,
erfüllt ist und wenn genügend erfüllt sind,
können wir sagen,
ja,
es ist wahr
Also prinzipiell hätte man relationale Programmiersprachen auch andersrum bauen können,
dass man einen Vorwärtsverketten macht. Also man sucht einfach nach Dingen,
die etwas warm machen. Und das ist das,
was wir im General Program Sulver haben und den behandeln wir,
wenn wir mit Prolog durch sind, ja.
Dann gucken wir uns den General Coplin Sulver nochmal an,
da haben wir Forward Chaining, ja. So,
und die Syntax, die im Prolog verwendet wird,
der Pfeil nach links, der soll tatsächlich sagen,
ja, Regeln werden mit Rückwärtsverkettung ausgewertet,
So, aber man kann es ja auch als Implimär,
Implikationsfeil lesen und hat damit die Deklarative Semantik von Pro Lock.
Corona-Beziehung in den Regeln, machen wir das solche Second
Score spielt und nicht jeder mag entweder kratzen oder.
Kommen wir dazu hin? Also die simple Antwort darauf ist schlichtweg,
man schreibt zwei separate Regeln. Das oder in Pro Lock
machen wir einfach dadurch, dass wir alternative Regeln hinschreiben.
Es wird die eine oder die andere genommen, ne?
Alles gute Fragen.
Gut, also was wir hier,
kommen wir jetzt nochmal zu einer Minklatur. Also das ist,
was wir hier stehen haben, ist eine Klausel, ja?
So. Und der linke Teilausdruck heißt der Kopf der Klausel.
So. Und der rechte Teilausdruck heißt der Körper der Klausel,
ja, also rechts von diesem Apparator hier.
Und man kann einfach sagen, ein Faktum,
das ist eine Klausel, die keinen Körper hat.
Körperlose Klauseln. Also solange wir, ein Fakt ist schlichtweg,
eine Klausel, wo es überhaupt keine Vorbedingungen gibt,
die gelten immer.
Da ist die Seite der Vorbedingungen leer
Und so, eine Klausel sichert uns eben zu,
dass der Kopf der Klausel wahr ist,
wenn alle Vorbedingungen im Klauselkörper wahr sind.
Was wir hier sehen, ist ein Und. War eben
schon nach dem Oder gefragt worden. Also wenn dir hier einfach
mehrere Bedingungen hinschreibe, müssen die alle gemeinsam wahr sein,
damit dies hier für die Variable X erfüllt ist.
Also für alle Ex-Schließe, das Kim-X-Markt,
wenn bewiesen werden kann, dass X-Liehmark und das X-Kim mag.
Genau, also wir müssten versuchen,
beides wahrzumachen und dann können wir sagen,
Kim mark
Ja. Also wenn das, was rechts steht,
ist ein großes und, ja, die Vorbedingungen,
die rechts sind, alle mit uns verbunden.
Und wenn nicht einfach alternative Klauseln hinschreibe, dann sind sie mit oder verbunden.
Ja. So, aber jetzt zum Kasus Knususus,
wie kommen die Werte für X zustande? Der Prozess,
der das macht oder der Algorithmus, ist die Unifikation.
Wir kennen sowas Ähnliches schon aus Eliza, ne?
In Eliza hatten wir ja Anfragen gestellt an unseren Doktor in
die Leisa und der hat einfach mit Pattern Matching geguckt.
Passt diese Frage zu einer bekannten Frage,
die ich habe
Ich kann Variablen extrahieren und dann generiere ich eine Antwort.
Unifikation ist sehr ähnlich. Man nimmt die Anfrage als Muster
und versucht, sie anhand der Datenbasis,
die Variablenbindungen herzustellen, die diese Anfrage wahrmachen.
Der Unterschied zum Pattern-Matching ist Pattern-Matching, ist eine funktionale Sache.
Die geht nur in eine Richtung. Unifikation geht eben in
alle Richtungen. Die ist symmetrisch. Bei der Unifikation dürfen
beide Seiten Variablen enthalten und so können Variablen auch mit
anderen Variablen unifiziert werden.
Das können wir jetzt mal
ein Beispiel anschauen
Beim Pattern-Matching würden wir, hätten wir geschrieben,
unser Muster ist X und Y. Ja,
und die Anfrage, die wir haben wollen,
ist 2 plus 1 und jetzt wollen wir Bindungen erfahren.
Wir haben noch keine Übergaben, nur beiden Links.
Und wir sehen jetzt, dieses Muster X plus Y
passt beim Pattern-Matching, wenn wir Y an eins binden.
Und X an 2 binden, ja.
Bei der Unifikation könnten wir die Variablen auf beiden Seiten haben.
Also sowohl bei dem, wonach wir fragen,
als auch nach dem was wir in der Datenbasis haben.
Und da könnte es eben passieren, dass X mit
zwei unifiziert wird und Y mit eins, ne?
Die Variablen sind in beiden Teilen. Ja, das ist
rein symmetrisch. So, wann unifiziert etwas?
Das können sie sich für die Klausur ins Gebietbuch schreiben,
weil es im Regelsatz etwas unifiziert, wenn die Stelligkeit stimmt, ja?
Wenn wir hier eine Liste von möglichen Werten haben,
dann muss die, das hier ist dreistellig,
das ist auch dreistellig, also kann es undifizieren.
Wenn die Namen der Prädikate stimmen, also wenn das,
was sie identifiziert wird, Fakten sind,
die mit dem Namen eines Prädikats beginnen,
muss der Prädikatsname stimmen
Als drittes müssen gleiche Variable gleiche Werte bestimmen.
Ja, wenn gebunden an gleiche Werte gebunden werden.
Also ich kann nicht X an einer Stelle für den Ausdruck
ein Eins binden und an der anderen Stelle an zwei.
Ja, das geht nicht. Also Stelligkeit muss stimmen,
Namen der Prädikate müssen identisch sein, gleiche Variable, gleiche Werte.
Hier haben wir eine Relation F, ja. Und die können wir mit F von nix,
können wir unifizieren mit F von Y, indem wir hier feststellen,
Die Variable X ist identisch mit der Variable von Y. Nur wenn wir sagen,
X und Y sind dieselben, haben denselben Wert,
dann identifiziert das Ganze.
Der hat Stimmen, Stelligkeitsstimmen, Predikazenname stimmt.
Und indem wir zwei Ausdrücke unifizieren,
wo an derselben Stelle beiden Teilen, unterschiedliche Variablennamen stehen,
können wir die Identität von Variablen ausdrücken.
Wir können sagen, ah gleich B.
Das geschieht über die Unifikation
Und wir können Variablen auch unifizieren, solange,
wenn sie noch gar keinen Wert haben.
Es wird einfach festgehalten, die müssen gleich sein.
Und wenn später, im Back-Tracking und so weiter,
dürfen eben nur Lösungen gefunden werden, weil wir wissen,
dass beide Variablen gleich sind.
Mal ein Beispiel, etwas komplizierteres Beispiel für die Unifikation.
Ach so, ich wollte noch festhalten,
wenn sie in die SE3 bebreitschauen, finden sie da pro Log in Recket.
Und sie finden dort ein Modul, das Unifizieren kann.
Und da gibt es einmal
die Funktion Unify
Können sich den Code mal angucken, dass das eine wirklich schicke Baumrekursion ist.
Und diese Funktion Unify, wir verwenden sie hier einfach,
um zu sehen, wie wir in Pro-Log das gemacht haben,
da können wir eben zwei Ausdrücke übergeben, die unifiziert werden sollen.
Wir haben einmal diese Struktur und einmal diese.
Ja. So, und das erwarten wir jetzt.
Predikaznamen gibt es gar nicht, also sind sie gleich.
Die Ständigkeit stimmt ein, zwei, drei, vier, fünf, ja.
Wir stellen jetzt fest, das kann nur unifizieren,
wenn wir festhalten, X ist gleich A, ja.
Und jetzt halten wir fest, es kann nur dann stimmen,
wenn Y gleich A ist. Also wissen wir daraus schon mal,
A, gleich X sein muss, Y gleich A, sein muss.
Und hier sehen wir, das geht auch nur gut,
wenn Y gleich Null ist. Und das heißt,
wir haben hier ein dreifaches Resultat, Y gleich Null,
X gleich Y und A, gleich X. Ja?
Und alle drei Werte sind Null. So. Die zweite Funktion,
die Sie in diesem Modul finden, was unifizieren kann,
das ist Unifire, das ersetzt alle Variablenbindungen,
die wir haben, durch die gefundenen Werte.
Und der würde uns hier jetzt, wenn wir diese
beiden Ausdrücke unifizieren, als unifizierten Ausdruck des Resultats geben,
X, das ja 0 plus 0 gleich Null
So, haben wir eine tolle Aussage rausgekriegt.
Nach 0 plus 0 gleich 0. Sieht so aus,
als würde pro Logmathematik machen, tut es aber nicht, ja.
Das ist rein syntaktisch. Also eine reine lexikalische Ersetzung.
Die Therme werden nicht ausgewertet. Also wenn wir dasselbe Spielchen hier
nochmal treiben mit A plus A gleich 2 und X plus Y gleich Y,
dann würden wir eben rauskriegen 2 plus 2 gleich 2.
Nach derselben Logik. So, bei dem,
ich reite ein bisschen auf dieser Unifikation herum,
weil das ist einer der beiden wichtigen Kerne von der operationalen Semantik von Kolok.
Man muss verstanden haben, wie Unifikation geht,
sonst kann man sie nicht benutzen,
weil die Unifikation ist praktisch alles, was wir haben,
um überhaupt irgendetwas in Recke zu bewirken.
Egal, was wir tun, wir unifizieren.
Also das Unifikation ist die halbe Miete.
Die andere Hälfte ist die automatische Suche durch Backtracking.
Ich reite hier vor allem auf der Unifikation rum
Also Unifikation ist unser Mittel und Variablen zu binden.
Das haben wir jetzt schon gesehen. Wir erfahren Variable X,
hat denselben Wert wie Y,
Variable Y, hat den Wert 3 und so weiter.
Also damit können wir überhaupt eine Wertzuweisung an Variablen machen.
Wir können nicht einfach hinschreiben, X gleich 3. Außer wir
werden freche und benutzen den Ausflug in die funktionale Auswerteumgebung von ProLog
. Machen wir aber erstmal nicht. Also das heißt,
sie haben, solange sie rein Relationalprogrammieren,
können sie nie hinschreiben,
Also um Barriable zu binden, brauchen wir die Unifikation.
Wir schreiben einen Ausdruck hin und Unifizierenden mit allem aus dem Peter Werte reinkriegen können.
Wir benutzen es als Selektor für Teile einer Struktur.
Also wenn wir eine Liste aufgebaut haben,
wir wollen das dritte Element haben,
dann unifizieren wir diese Liste mit einer Struktur,
bei der an der dritten Stelle eine Variable steht und fragen diesen Variablennamen ab.
Damit haben wir den Wert. Man sagt nicht einfach,
gib mir aus dem Rekord das Element so und so,
sondern wir schreiben einen Ausdruck hin, der unifiziert wird,
wo an der Stelle,
wo wir den Wert wissen wollen,
eine Variable haben
Also hier erfahren wir, wenn wir das so schreiben,
dass der Wert Y gleich null ist, weil Y mit null unifiziert.
Also so fragen wir noch Werten von Waren,
nach Teilen von einer Struktur, eine andere Struktur mit Variablen hinschreiben,
mit Platzhaltern an den Stellen, wo wir die Werte brauchen.
Und wir konstruieren Strukturen. Warum? Ja,
wir haben hier die Struktur 0 plus 0 gleich null konstruiert.
Warum, indem wir gesagt haben, baue mir etwas,
das besteht aus der Variablen X und Y und bin de
Y ein Null.
Da ist dann rausgekommen, dass die Struktur das ist.
Also die Unifikation erzeugt uns Strukturen, sie gibt uns Teilwerte.
Und ist praktisch in seinem, unser Mittel, um in Pro-Log-Programmen Fragen zu stellen,
auf Werte zuzugreifen, höhere Strukturen aufzubauen. Ja,
und wir können auch noch den Test auf Gleichheit hinkriegen,
indem wir, wenn wir wissen wollen,
ob zwei Variablen gleich sind, unifizieren wir sie,
indem wir die beiden Variablennamen an derselben Stelle schreiben.
Ja, wenn die Unifikation gut geht,
wissen wir,
dass A
gleich Y ist
Kommt ihm jetzt wahrscheinlich etwas umständlich vor, all solche Dinge,
die man in imperativen Sprachen einfach hinschreibt.
Wir schreiben das X gleich Y, ja.
Hier schreiben wir zwei Ausdrücke, unifizieren sie.
Und dann erfahren wir, ob die Variablen gleich sind.
Ja. Mhm
Die stehen in derselben Datenbank drin. Das gucken wir uns
gleich am Beispiel an. Da kann ich das besser erklären.
Versuchen Sie an Ihre Frage zu erinnern. Willst du an
der Stelle sind? Also der Zweck von all dem ist,
ja, Unifikation, wir binden damit Variablen.
Wir selektieren Teile von Strukturen. Wir bauen Strukturen und wir
vergleichen, ob Dinge identisch sind.
So, also wir schreiben jetzt ein Programm in pro Log.
Also wir schreiben relevante Relationen zwischen dem, worum es uns geht, auf.
Sichern Sie zu als Klauseln, entweder als Fakten, oder als Regeln.
Und die tragen wir ein mit dem Insert-Makro in eine Datenbank, ja.
Und dann benutzen wir das Programm, in dem wir Interpritter-Anfragen stellen,
ja. Die Datenbank ist fertig, hat ihr Schema,
da stehen all diese Dinge drin,
wenn wir es erstmal nur als Datenbank benutzen wollen und dann fragen wir, ja.
So, dann wird pro Log sich bemühen,
uns zu sagen, ob die unsere Anfrage,
die wir haben, ist sekramento die Hauptstadt von Kalifornien, ja.
Es wird mit Backtracking all die bekannten Fakten durchsuchen und versuchen,
Wenn es kein direktes Faktum findet, Regeln anzuwenden, um zu beweisen, dass es so ist.
Und es wird häufig verschiedene Möglichkeiten geben,
wenn sich Prolock jetzt entscheiden muss,
welche Regeln werte ich denn nur als erstes aus,
dann merkte sich ein Entscheidungspunkt und an der Stelle ist das Despekt-Tracking ein,
wenn ein Versuch der Fahrt zu beweisen, dass Sakramento,
die Hauptstadt von Kalifornien, ist schiefgegangen ist,
wird es eben zurückgehen mit Backtracking bis zu der Stelle,
wo es eine andere Alternative hatte
Gut, und deshalb heißen Teilklauseln in der Anfrage,
mit denen wir etwas fragen, auch Ziele,
weil das Ziel eben darin besteht zu beweisen, dass dem so ist.
Ja, jetzt kommt das zweite Makro,
das ich eingebaut habe, um damit eine Special-Form zu haben,
mit der wir Anfragen machen können.
Also wir haben einmal der Fmakro verwendet, um das Sird-Makro zu schreiben,
mit dem wir Zusicherung in die Datenbank schreiben,
Fakten zu sichern, Regeln zu sichern.
Und jetzt haben wir das zweite Makro,
das habe ich jetzt auch mal mit Dev Makro hier hingeschrieben,
Dev Makro ist eine Special-Form aus
Ein Zelos, ja. Death Macro. Und da definieren
wir dieses Macro, das mit einem Fragezeichen wird.
Das soll also das Fragezeichen-Macro sein. Das hat beliebig viele
Ziele. Ziele, die wir beweisen wollen. Also wir
fragen, gilt das? Und was ruft es aus,
aus dem Pro-Log in Recket-Paket, ruft es die Funktion auf Top-Level-Proof.
Es wird versucht zu beweisen, dass diese Ziele wahr sind.
Und dann werden die Variablen ersetzt mit Unifeier und eingesetzt und wir kriegen die Antwort.
Das ist im Wesentlichen, was dieses Macron macht. So,
von der Syndax her, wir haben hier ein Quasi-Quo.
Das ist nicht das normale Quotierungszeichen, sondern ein Quartierungszeichen,
das an allen Stellen, wo ein Komma in dem Ausdruck steht,
die Dinge auswertet, bevor sie da eingesetzt werden.
Ja, das praktisch ankrotiert. So, gut,
eine Anfrage, machen wir es mal doch,
hier aus dieser Entfernung, die gilt als wahr,
wenn die Zusicherung in der Datenbank das unterstützen.
Ja. Und in allen anderen Fällen kriegen wir die Antwort
Not zurück.
Ja,
abgeschlossene Welt
Also wenn unsere Anfrage von Pro-Log beantwortet werden könnte,
dann druckt es uns als Antwort alle Variablenbelegungen aus,
die unsere Anfrage warm machen, also den logischen Ausdruck erfüllen.
Und dann kommt ein Yes, so. Und wenn man
jetzt den Verdacht hat, dass es mehr Lösungen gibt,
gibt man ein Symmikol an ein und dann sucht Pro-Log nochmal von einem weiteren Entscheidungspunkten,
die noch da sind im Black-Drecking und sucht nach weiteren Lösungen.
Und irgendwann sagt es No, ja,
wenn da nichts mehr ist. So, jetzt gucken wir
uns mal Pro-Log als Daten
Banksprache an, mal mit einem ganz simplen Datenbank,
wo wir einfach einen Familienstammbaum haben. Also relationale Datenbank,
wo einfach nur Familienverhältnisse beschrieben werden. Wir können fragen,
wer sind die Kinder von wem und welche,
wer hat welche Eltern und Großeltern und so weiter. Also unsere Ahnentafel,
wir betrachten hier den Herrn Peter und dessen Mutter heißt Vera,
Vater heißt Victor,
so die Großeltern sind Mallorca und Martin und Mona und Mike und dann die Urgroßeltern,
Nora, Norbert,
Nina,
Nick und so weiter.
Dass also die Antafel, die müssen wir jetzt im Pro-Log mal beschreiben,
wir können Kommentare im Pro-Log in Drecket reinschreiben,
wie wir es in Drecket gewöhnt sind, ja.
Also hier schreiben wir, das ist Predikatschema. Wir haben
die Relation Eltern und die Argumente erfolgen in der Reihenfolge Mutter,
Vater, Kind. Ja, so die Eltern von Peter,
da schreiben wir jetzt also in unseren Datenbankfeil rein,
Zusicherungsmakro Assert, Parents von Peter sind Vera und Victor, ja.
Und jetzt für die Großeltern, die Eltern von Maya von Vera,
also von der Mutter sind Martin und Maya und Mona und Mike,
so Urgroßeltern und so weiter.
Also hier haben wir jetzt erstmal einfach nur Fakten zugesichert.
Ja, so würden wir das aufschreiben und haben dann mit diesen Stammbaum hier.
Ja, und jetzt können wir schon mal anfangen,
nach irgendwelchen Eltern zu fragen.
Hier wenden wir jetzt unsere Anfrage, Makro. Ja,
das geben wir in Recked im Enteurbretter ein, schreiben wir.
Klammer auf, Fragezeichen und dann kommt hier der Ausdruck hin,
von dem wir wissen wollen,
hat Peter Eltern und wenn ja,
wie heißen sie,
haben wir
hier gefragt
Und was wird als unser Brüllock in Reckett sagen? Ja,
die Aussage, dass Peter Eltern hat, es war,
wenn die Mutter, Vera heißt und der Vater Victor, ja?
Das ist das, was wir zurückkriegen. So,
das ist eine simple Datenbanksuche, ne? Wenn wir jetzt
nach Großeltern fragen wollen, dann verwenden wir einen Datenbank join.
Ja, das können wir einfach dadurch machen, dass wir
in der Anfrage hier alles mit einem großen und verbinden.
Also wenn wir in einer Anfrage mehrere Vorbedingungen nennen,
also mehrere Ziele, müssen wir präzise sein. Ja,
hier haben wir drei Ziele, da müssen die alle
gleichzeitig erfüllt werden und wir kriegen die Variablenbindung, die alle drei Ziele gleichzeitig erfüllen. Also hier ist unser Ziel,
wir wollen Variablenbindungen für Peter haben, sodass wir Vater und Mutter kennen,
ja, aber nicht jeden und nicht jede Vater,
Mutter, sondern wir wollen anschließend auch noch Großmutter und Großvater,
mütterlicherseits und Großmutter und Großvater väterlicherseits haben und dann erfahren wir jetzt,
okay, das ist also alles wahr,
wenn wir als Für die mütterliche Seite, Krentner und Grenzpaar,
Marion Martin nehmen und für die väterlicherseits Mother und Oma,
ja, Vera, Mona,
Mike und den Vater.
Und wir erfahren, es gibt nur eine Lösung.
Wenn Sie mir Kullern angeben, um nach weiteren Lösungen zu fragen,
stell dir fest, er hat keine alternativen Vorfahren, ja?
Also was wir hier haben,
ist ein Join von Datenbankanfragen und das kriegen wir einfach dadurch,
dass wir drei Ziele nacheinander nennen, ja?
Wir können damit auch einfach eine Relation komplett aufzählen. Ja,
das geht in richtigen Frohlock, ganz genauso,
indem wir einfach die Instanzisiierungsvariante wählen,
dass keine der Plätze hier vorbelegt sind, sondern überall Variablen stehen.
Und dann kriegen wir hier vollkommen aufgelistet durch diese Frage,
was alles an Fakten über Eltern und Kinder bekannt ist.
Was ganz nützlich ist und für lisbaren Kot ist,
ist das für anonyme Variable haben.
Anonyme Variable werden gebunden, wie alle anderen auch,
aber wir sagen, uns interessiert das Ergebnis nicht und unterdrückt
sie bitte eine Ausgabe
Und die anonymen Variablen im Vorlock verreckelt, ist,
dass wir statt eines Variablen namens mit Texte einfach nur in Fragezeichen reinsetzen.
Also wenn wir jetzt wissen wollen,
wer ist die Mutter von Walter und Vater ist uns egal oder wir zweifeln,
ob es einen gibt,
dann schreiben wir da einfach ein Fragezeichen an die Stelle
und dann ist die Ausgabe eben nur Mother Petra,
ja?
Wenn wir,
wer wird das tun
Bereits zweifach. Ja, bei dem ersten Fall,
wir haben jemals zwei Tage 40 Grad Fett, hätte ich auch geglücklicherseits aufgezählt.
Ja, also solange wir hier Semikolan eingeben,
werden alle alternativen Lösungen, die in der Datenbank auch drinstecken, aufgezählt.
Aber irgendwann sagt Recket No und das heißt,
weitere finde ich nichts, ja.
Sehr empfindlich eingestellt, ne? Wow, wo kann ich
das ändern
Low Bettery. Weiß nicht. Die Frage. Lautstärke dürfte da eigentlich
nichts dran erinnern. Das ist nochmal ein Ding, aber ich glaube,
es ist eher ein Handy, was da irgendwie zwischenfunkt.
Ah ja, toll. Gut. Also,
was sie aus dem Datenbankvorlesungen sicherlich auch kennen, ist,
dass man Relationen, die ziemlich viele Teile haben,
dass man die gern kompakter haben möchte für eine andere Sicht auf die Datenbasis.
Also wenn uns eben nur Vater oder nur Mutter interessiert und so,
dann können wir diese Relation projizieren, auf welche mit Winden, an der geringeren Stelligkeit.
Und das können wir einfach machen, indem wir weitere Relationen einführen. Also wir haben die Elternrelation,
da haben wir ja Mutter,
Vater in Beziehung zu einem Kill und wenn uns der Vater nicht interessiert,
dann führen wir eben eine neue Relation Mutter von ein,
ja, Mother, mit nur der Variable und Kind und die ist erfüllt,
es Eltern gibt,
wo die Mutter hier auch auftaucht.
Also hier sieht man die Wirkung der Co-Referenz,
die stellt die Beziehung zwischen Variablen her. Oder eine Vater-Relation,
wo hier die Mutter als zu ihr ignorierende Variable angegeben wurde.
Gut. Nächstes Beispiel, wir wollen jetzt mal versuchen,
Prolog als deduktive Datenbasis zu verwenden.
Also wir haben bisher nur die Eltern modelliert,
weil wir wollen jetzt gezielt nach einem Großeltern fragen.
Und jetzt müssen wir also definieren, was sind denn
die Großeltern von Kindern
Ja, und das können wir rekursiv machen. Oder zunächst
mal hier direkt programmiert für die allgemeinen Vorfahren, müssen wir rekursiv werden.
Die Großeltern gehen auch ohne Rekursion. Die Eltern sind entweder
Vater oder Mutter. Die Großeltern sind die Eltern der Eltern
. Und dann rekursiv werden wir, indem wir sagen,
Vorfahren sind Eltern der Eltern oder die Eltern der Vorfahren.
Gut, und das gucken wir uns mal an, wie wir das hinkriegen können.
Eine allgemeine Elternrelation. Jemand ist ein Elternteil von einem Kind,
wenn es entweder die Mutter ist,
Und die haben wir die Antwort auf Ihre Frage nach dem Oder.
Die andere Möglichkeit ist, dass das Elternteil der Vater ist.
Ja, wir schreiben es einfach zweimal hin. Einmal für die Mutter,
einmal für den Vater und haben damit eine Elternrelation,
die beides beschreibt. Also hier sagen wir,
jemand ist ein Elternteil von einem Kind, wenn es die Mutter ist.
Es taucht in der Mutterposition in der Elternrelation auf.
Oder es ist der Vater. Es taucht in der Vaterposition,
in der Elternrelation, für dieses Kind auch.
Und wann ist jemand Großelternteil, Großvater, Großmutter,
dann, wenn Also irgendein Element, Grand, Grandfather,
Grandmather, ist eben Großelternteil zu dem Enkelkind.
Wenn es ein Elternteil von einem Eltern des Kindes ist,
ja. Hier verknüpfen wir das jetzt so.
Also der Großmutter oder Großvater ist ein Elternteil von einem Eltern,
von einer Variable Eltern des Kindes und dieses Elternteil des Kindes
taucht hier in der Perrentrelation für dieses Großenkelkind auf.
So, also damit haben wir hier jetzt deduktiv beschrieben,
was Großeltern sind, ja.
Und wenn wir jetzt ganz allgemein Vorfahren beschreiben wollen,
dann sagen wir, es gibt zwei Fälle.
Jemand ist Vorfahre zu einer Person. Also hier. Dieses
Freddy Sessel, ja, ist Vorfahre zu der Person Person,
wenn es ein Elternteil dieser Person ist.
So, das ist unsere Indoorekursionsverankerung, ne. Oder aber,
wenn wir beweisen können, dass das Dass diese Person das
Elternteil von einer Person ist, die Vorfahrer der Person ist.
Eine Stufe weiter. Da gehen wir in die Rekursion.
Ziel so eine Atmoduktionsabsatzrufe zuerst sagen, zuerst definieren wir,
was Stufe einsetzt. Genau, genau das machen wir.
Hier ist sozusagen die Induktionsverankerung. Hier haben wir einen Abbruch
für die Suche. Und hier sagen wir, regorsiv,
was man noch versuchen kann,
wenn ich nicht einen direkten Vorfahren finde,
dann versuche ich zu beweisen,
dass eine Person Vorfahre ist,
indem ich einen Schritt weiter zurückgehe und mir
die Eltern anschaue
Und wichtig ist hier, dass man so rumschreibt,
hier erst versucht, mit Pretis, Sessor,
einen Elternteil zu finden und dann perent aufzurufen.
Wenn wir das hier umdrehen, also den Rekursionsschritt erst machen und dann den Teil,
der nur einen Schritt weiter bringt, dann haben wir ein Problem.
Ja. Hatte das sein jetzt hier zum Beispiel eine Konzentivation? Wenn wir das so definiert hätten,
kriegt man zum Beispiel jetzt eine weitere Wegblattgürt,
die fragt von all denjenigen, die noch euer Pandemie sind,
für eine all diejenigen, Das sind jeder mit der zu erleben,
das ist ein Vorbarmens.
Ich könnte mir da eine Gemeinde in der Vorfahrt. Kann man alles machen,
man muss nur höllisch aufpassen, wenn man hier in Backtracking geht,
dass das nicht eine tiefen Suche in einem unendlichen Pfad wird,
wo keine Lösung ist.
Also man muss immer versuchen, das Surren aufzusetzen,
dass man etwas konkret Prüfbares zuerst macht.
Wie ist Eltern von etwas, was ich hier habe?
Und dann kann man in die kompliziertere Rekursion gehen.
Also wir haben hier erstmal nur ganz simple Beispiele.
Wenn Sie selbst versuchen, Prolog zu programmieren, werden Sie merken,
das eigentlich einfacher ist, aber man muss lernen, relational zu denken.
So, hier fragen wir jetzt mal nach den Großeltern von Peter,
ja, und dann erfahren wir hier, dass es vier gibt.
Und wenn wir noch ein Vorfahren fragen,
da finden wir nicht viele, was nicht heißt,
dass es seit Adam und Eva nicht viele gegeben hätte,
aber die Datenbasis kennt eine zweite, ne?
Und wir haben jetzt nur Vorfahren definiert, aber wir können
das Ganze umgekehrt Bericht verwenden und nach den Nachkommen fragen, ne?
Dann nehmen wir die Vorfahrenrelation Pre-Decessor und setzen einfach hier an der Stelle,
wo die Vorfahren stehen einen festen Namen ein und fragen dann nach dem Nachkommen.
Ja? Also das ist das Schicke,
was richtig Spaß bringt in pro Log,
dass wir die Datenbasis einmal aufsetzen und dass wir die richtungsunabhängigkeit
haben und sie vorwärts, rückwärts beliebig durchsuchen können.
So, halbe Stunde haben wir noch.
Versuchen wir es mal als Inferenzmaschine zu verwenden,
indem wir uns jetzt mal ein richtiges Beispiel anschauen,
wo wir ein bisschen mehr programmieren.
Also zum einen hier erst nochmal das große Beispiel einsteigen, etwas komplizierter.
Wir erweitern unsere Ahnentafel. Also bisher hatten wir nur diesen
oberen Teil, wo wir zu Peter alle vorfahren haben.
Jetzt nehmen wir mal an, der hat inzwischen geheiratet,
seine Petra und hat jetzt auch ein paar Nachkommen,
sodass wir über Geschwister nachdenken können.
Und diejenigen, die Prüller kennen, die wissen,
der erste Stolperstein bei der deduktiven Sicht ist schon mal das Geschwisterprädikat oder Zwillingsprädikat.
Da kann man schon die ersten bösen Überraschungen erleben.
Also wir haben ja jetzt erst mal Petra und Peter
im Interesse unserer Rente ziemlich viele Nachkommen vorgesehen.
Wilma, Werner, Winni, Walter, Wilfrit.
Ja, und jetzt definieren wir, was Geschwister sind.
Ja, wann sind denn zwei Leute Geschwister? Sagen wir
erst mal, ohne jetzt über geschiedene Elternteile und so nachzudenken.
Wir sagen, jemand ist A und B,
sind Geschwister, wenn sie dieselben Eltern haben.
Ja, und wie sagen wir
Das geht so teppt. Hören Sie mich jetzt? Ja, wunderbar.
Guter technischer Service hier. Okay, also. Wir wollen wissen,
ob X und Y Geschwister sind und sagen erst mal ganz klassisch,
die sind Geschwister, wenn sie dieselben Eltern haben, ja?
Also der Mutter und Vater von X sind dieselben Mutter und Vater
wie von Y, da sind X und Y Geschwister.
So. Und jetzt fragen wir mal, was sind die Geschwister
von Walter
Und ja, und dann kriegen wir raus, okay,
das ist wahr für Wilmer, für Werner,
für Winnie, für Wilfried.
Aber Walter ist sein eigenes Geschwister. Bisschen komisch, ne?
Wollen wir eigentlich nicht. Warum? Weil wenn wir für
X und Y Walter einsetzen, dann gilt in beiden Fällen,
dass Mutter und Vater gleich sind.
Also so haben wir es definiert, ja. Damit ist so
sein eigenes Geschwisterteil. Jetzt stehen wir so vor der Frage,
wir sagen, aber es sind keine Geschwister,
wenn es dieselbe Person ist.
Nicht, dass er als Schizophren ausgewiesen wird,
Zwei Sachen. Das war... In unserer Emotion kommt Geschwister
, haben wir jetzt unterwegs, Halbschwister. Ja,
ich sag ja, wir haben die klassische deutsche Familie.
Das kann... Das ist beide Varianten. Das ist noch
eine letzte Funktionelle, wo man sagt, X-Bot.
Richtig. Und genau das wollen wir uns jetzt angucken,
wie wir das machen wollen.
Wir drücken mal aus, dass etwas nicht leicht ist.
Und dazu führen wir einfach
eine Gleichheitsrelation ein
Ja. Und das können wir über die Unifikationen machen, ja?
Also wir wissen ja, zwei Strukturen sind gleich, wenn sie unifizieren.
Und wir können ganz simpel hier definieren. X ist gleich Y,
also eine Relation Gleichheit führen wir ein, indem wir sagen,
es ist erfüllt, wenn diese beiden Dinge gleich sind, ja?
Und Unifikation verlangt das gleiche Variable an gleiche Werte gebunden werden.
Das heißt, was wir hinter dem Gleichheitszeichen schreiben,
muss zum gleichen Wert ausgewertet werden,
ja?
Und wir können auch noch eine
Ungleichheitsrelationen einführen, indem wir sagen, not equal.
Not ist voreingebaut als festes Sprachelement in pro Log.
Und damit ist dies hier negiert. Und mit diesen beiden
zusätzlichen Relationen, also ungleich und gleich,
kommen wir jetzt zu unser Zwillingsprädikat nochmal anders schreiben oder das Sipplingsprädikat.
Wir werden jetzt einfach die Eltern von X müssen M und
F sein und die von Y auch.
Wir verlangen also, damit die Eltern von X und Y
sind gleich und wir verlangen das X und Y ungleich sind.
Und wenn wir das so machen, dann ist der Walter
hier aus der Liste weg. Weil hier dieses Ungleich erfüllt ist,
also Walter wird nicht mehr als sein eigener Bruder gelistet.
Ja, jetzt können wir uns mal ganz allgemein anschauen,
wie wir logische Relationen im Kurlock ausdrücken.
Also die Konjunktion ist implizit in der Liste aller Prämissen einer Regel.
Also was rechts steht, ist implizit durch und gebunden.
Die Disjunktion, das oder, nicht das und,
kriegen wir, indem wir einfach alternative Regeln aufschreiben
Und die Negation wird durch den Nord-Operator ausgedrückt.
Und ein Not ist erfüllt, wenn wir in der Datenbasis
nicht beweisen können, dass es wahr ist.
Dann ist das negiert, der erfüllt. Es ist,
wir haben es als explizites Sprachelement. Und wenn in der Datenbasis
keine Lösung gefunden wird, dann heißt es nein. Ja,
das ist, es sagt uns, wir erfahren wirklich nur,
dass es nicht in der Datenbasis beweisbar ist.
Wir wissen nicht, ob es mit mehr Regeln
beweisbar wäre
Wir haben noch nicht drüber gesprochen über Variablen. Also wir
kennen in Reckett das Variablen ziemlich kompliziert, eingesetzt werden können.
Wir haben Verschattung, Gültigkeitsbereiche. Wir haben Letzt,
wir haben globale Variable und so weiter. In Brüller haben wir
ganz simpel nur die Variablen innerhalb einer Klausel. Ja,
der Gültigkeitsbereich einer Variable ist die Klausel, in der sie erwähnt wird.
Und den alternativen Klauseln, es ist eine andere Variable.
Also wenn wir eine Klausel definieren und der taucht eine Variable auf,
dann gilt sie Ist ihr Scope, ihr Sichtbarkeitsbereich,
diese Klausel und außerhalb, da können wir noch so oft X sagen,
es ist ein anderes X.
Und wenn sie mal gebunden wurde durch Unifikationen, behält sie ihren Wert.
Also das ist einfach und schick. Und da versuchen wir
jetzt mal ein bisschen rekursiv mit einfachen Beispielen zu programmieren,
die zum Beispiel Member in Recket,
wenn wir Mitgliedschaft in einer Liste testen wollen,
da würden wir einfach rekursiv Element für Element die Liste durchgehen und immer sagen,
Ist es das gesuchte Element oder nicht?
Ja, das ist gerichtet. Die Member-Relation in Prolock
kann viel mehr, die kann uns auch Listen konstruieren.
Und wir können die Mitgliedschaft in der Liste in Prolock so ausdrücken.
Das Element der Liste, wir wollen wissen, ist ein Element,
Element der Liste, der steht in der Redaktion,
es ist Element der Liste zu einer Liste.
Es ist entweder das erste Element oder es ist Element der Restliste, ja?
So, den ersten Teil, den schreiben wir hierhin. Member,
irgendein Item, ist Mitglied der Liste Und dieser Liste,
die aus dem ersten Element besteht,
dann kommt hier jetzt die In-Fix-Notation vom Kunstapparator, dieser Punkt,
ja, und dann kommt der Rest der Liste.
So schreiben wir das Muster auf. Ein erstes Element und
eine Restliste, ja. Also, wenn dieses Item gleich
dem ist, dann ist dieser Teilausdruck wahr, ja.
Die Klausel ist erfüllt und Item wird gebunden ins erste Element der Liste.
Wenn das nicht wahr ist, Kindernächste Entscheidungspunkt, jetzt prüfen wir nämlich,
kommt es im Rest der Liste vor und wie machen wir das?
Wenn wir eine ein Element haben und haben eine Liste,
die beginnt mit X und hat einen Rest,
ja, dann ist dieses Item-Mitglied dieser Gesamtliste,
wenn es im Rest ein Element ist, ja,
der Test rufen die einfach rekursiv.
Dieses, diese Relation wieder auf. Member, Item,
Rest, ja, also er steht zweimal da und wir
haben die Rekursion hier hingeschrieben.
Und das können wir mehrfach machen, mal einfach auf Testen testen.
Wir stellen hier mal die Anfrage. Ja,
ich habe hier jetzt mal Recket Off gemacht
Impro-Log für Recket und tippe hier ein, Klammer auf,
Anfrage-Operator und wir schreiben rein Member 1,
kommt es denn in der Liste 2, 1, 3 vor?
Sie sehen hier übrigens Votierungszeichen, brauchen wir hier nicht.
Das ist in dieser Syntax implizit, ja. Und da
erfahren wir einfach yes, ja. Eins wurde drin gefunden.
Wir wissen nicht wo, aber es steht drin. Oder wir fragen,
kommt die 1 vor in 2, 1, 3,
1, wird gesagt, ja, und wenn wir jetzt das Simicolan eingeben,
dann erfahren wir, es kommt nochmal vor.
Weiter hinten und dann erfahren wir No. Wir wissen jetzt
also, es ist zweimal gefunden worden,
Jetzt können wir sehen, wie wir Unifikationen als Konstrukte benutzen können.
Wir wollen eine dreielementige Liste bauen, die irgendwo eine Eins enthält.
Also wenn ich das so schreibe, eine Anfrage,
er kann eine Liste existieren, die in der Relation Member 1
zu der Liste steht und die aus drei beliebigen Elementen besteht.
Da bauen wir jetzt eine solche Liste zusammen. Und wir erfahren,
diese Relation ist erfüllt, wenn wir die Liste so bauen,
dass die Variable A irgendeinen Wert eines hat,
die Variable B irgendeinen Wert nicht festgelegt und die Variable,
sie, auch irgendeinen Wert hat.
Diese Liste, die wir dann kriegen, hat eins zum Element.
Ja, und dann wird das Similkulan eingeben,
noch weiteren Lösungen zu fragen, dann erfahren wir,
ah, kann irgendeine Variante, unanonyme Variable sein?
An der Stelle B, da strahlt meine Einzelnen und für den Rest wieder irgendwas.
Auch dann haben wir eine dreielementige Liste, nicht eine Eins hat.
Und hier an der dritten Stelle zähl gleich eins,
ja, und dann die weiteren Lösungen sind null.
Also was hier nicht passiert, ist,
dass alle möglichen Symbole der Welt aufgezählt werden,
dann wäre die Antwort nämlich ziemlich endlos, sondern es wird abgekürzt,
indem man sagt, nimm irgendeine Variable hier hin.
Ist mir egal, was es ist. Aber an der
Stelle, ah, schreibt mal den festen Wert einzeln.
So, die hohe Kunst in Recket war ja,
dass wir mit Funktionen höherer Ordnung Funktionen als Argument hatten oder als Resultat.
Und das können wir natürlich auch in der Welt der Relationen machen.
Relationen, die Relationen zum Argument nehmen. Und die werden
für uns auch da die Rolle der Kontrollstrukturen haben.
Und da schauen wir uns jetzt allerdings wirklich nur das Allereinfachste
an,
zum Beispiel Find All
Suche alle in meiner Datenbasis alle Ausdrücke, die wahr sind unter einer bestimmten Prämisse.
Das macht Falt auch all für uns, als Prädikat zweiter Ordnung.
Wie sieht ein Feind all aus? Find all,
da kommt ein Term, ein Ziel und eine Liste.
So, die Liste ist eine, ist unser Resultat.
Da stehen nämlich alle instanziierten Varianten drin,
die wir für den gegebenen Thermen hier bauen können,
indem wir dieses Ziel beweisen.
Also wir geben hier ein Ziel an. Das Ziel führt dazu,
dass Variablen gebunden werden und mithilfe dieser Variablenbindung werden hier Therme konstruiert.
Und alle Therme, die wir bauen können aus den verschiedenen Arten,
wie das Ziel erfüllt werden kann, das kriegen wir als Ziel zurück.
So, und die Prädikate, die hier als Argument reingehen,
gehen hier in die Ziele ein.
Gucken wir mal, wie wir es machen könnten,
wenn wir zum Beispiel alle Vorfahren einer Person haben wollen
So, alle Vorfahren für eine Person mit ihren,
ja, Personen, und das sind die Ends,
ist das, und wir machen jetzt einen Find All,
haben hier an der Stelle Therm,
haben wir einfach nur die Variable.
Pretty Sessel, ja, beim Ziel geben wir an,
Pretty Sessel von, muss wahr sein,
für Predi Sessel an Person,
und hierhin kommen jetzt
die ganzen Vorfahren
Okay. Wenn wir jetzt, dieses All-Ancess,
das aufrufen für unseren Wald davon vorhin,
dann kriegen wir also das als Liste aller seiner Vorfahren gesammelt.
Oder wenn wir die Geschwister von Walter haben wollen,
statt sie einzeln mit jedem Fragezeichen neu kriegen zu können, Find
All bout uns eine Liste. Da würden wir also fragen,
Find All, der Therm ist einfach nur Geschwisterkind,
was erfüllt werden muss als Ziel ist,
Walter muss in der Relation Süpplingen zu diesem Geschwisterkind stehen und
wir kriegen die Liste Sipplings zurück.
Ja, Wilfried Windy Werner,
Wilma.
Mit all dem zusammen können wir uns jetzt mal dran wagen,
ein richtig knobeliges Rätsel zu lösen. Und das werden wir
das nächste Mal dann nochmal vertiefen mit einem etwas anderen Rätsel,
weil da können wir nochmal einen Rückschau halten und den über die Sprachelemente verwenden.
Also eins der typischen Knobelrätsel, die so im Scientific American immer auftauchen,
ist, hat das Zipra-Rätsel. Also die Domäne ist total dämlich,
aber man muss viel knobeln und das zu Fuß zu machen,
ist echt mühsam. Wenn wir es im Prolog programmieren,
ist es ein Klacks, zwei Folien und wir sind durch.
Gut, was ist das Rätseln. Es gibt fünf Häuser,
die stehen in einer Reihe und über die Einwohner jedes Hauses
erfahren wir ein bisschen. Aber in Regeln,
die von der Struktur her alle total verschieden sind, ja,
das lässt sich also in klassischen Imperativen sprachen unglaublich schwer formulieren,
weil wir einfach Regeln haben, die alles mögliche im Zusammenhang bringen.
Und im Prolock haben wir die alle einfach in eine Datenbasis
reinschmeißen, die damit zumüllen und sind fertig.
Ja, also diese Bewohner haben alle Einschränkungen bezüglich der Nationalität,
welches Haustier sie haben, was sie rauchen, was sie trinken.
Also das Rätsel stammt aus einer Zeit, als es noch
politisch korrekt war, zu rauchen und zu saufen.
Und die Frage ist, wer hat ein Zebra als Haustier
und wo wohnt der Wassertrinker
Gut. Und die Regeln, die im Scientific American gegeben wurden, ist folgendes.
Jedes Haus hat eine andere Farbe. Ja? Jeder Besitzer,
der fünf Häuser hat, eine andere Nationalität,
ein anderes Lieblingsgeschränk, ein anderes Haustier, eine eigene Zigarettenmarke.
So, und dann wissen wir, es wird gesagt,
die Engländer lebt im roten Haus.
Wir wissen, der Spanier hat einen Hund. Im grünen
Haus trinkt man einen Kaffee, der Ukrainer trinkt tät,
das grüne Haus ist direkt rechts neben dem Elfenbein farbenen Haus.
Der Winston Raucher hat Schnecken als Haustür,
im gelben Haus wird cools geraucht, im mittleren Haus trinkt man Milch,
der Norweger wohnt im ersten Haus links, Tester führt Raucher,
direkt der Nachbar vom Mann mit dem Fuchs.
Der Kultsraucher, direkt der Nachbar vom Pferdebesitzer.
Der Lucky Strike Raucher trinkt Orangensaft, Japaner raucht Paliaminz,
Norweger wohnt neben dem Blauen Haus.
Ja, und was war die Frage? Wo wohnt
der Wassertrinker und fährt ein Zebra als Haustier? Ja,
dann bist du ganz schön schwierig, da die Gedanken zu sortieren,
dass man das alles ordnet, ne?
Okay. Aber wie gesagt,
im Pro-Lock kann man so unterschiedliche Regeln sehr einfach schreiben,
ja, und das geht alles ziemlich simpel über Unifikation.
Also das Rätsel zeigt einem echt, wie mächtig die Unifikation ist.
Wir können jetzt erstmal die Unifikation nutzen als Konstrukt dafür Strukturen.
Wir definieren eine Hausrelation, die aus der Nationalität besteht,
dem Haustier, der Zigarettenmarke, die geraucht wird,
dem Getränk und der Farbe des Hauses. Wir definieren zwei Prädikate,
next to und benachbart ausdrücken zu können und I are right,
das soll die Relation sein, wohnt direkt rechts von. Also hier haben wir festgelegt,
all das muss in einem Haus geben und die Stützprädikate,
die wir mal einführen, ist gegeben eine Liste,
die Variable X ist benachbart zur Liste, zur Variablen Y,
wenn sie entweder direkt rechts von X ist in der Liste,
oder wenn das Umgedrehte direkt rechts ist, ja, ja,
diese beiden Varianten, dann sind X und Y direkt benachbart.
Haben wir hier ausgedrückt durch zwei Alternative, Relationen next to. Ja? Eireit,
das sagt, ist es direkt rechts davon,
das machen wir rekursiv, indem wir entweder sagen,
ja, die Liste beginnt damit, dass diese beiden Elemente,
Left und Reit direkt am Anfang stehen, dann kommt ein Rest,
oder aber es ist erfüllt im Rest der Liste,
wenn ihr vorhin irgendein X steht
Wir definieren noch die Identität. Das haben wir
schon mal gemacht, brauchen wir in diesem Programm wieder.
Und jetzt können wir alle 15 Regeln, die wir gesehen haben,
nehmen. Und das in eine Proloc-Klausel schreiben und das Ganze
so aufschreiben und jetzt sind wir fertig.
Ich bräuchte jetzt einen zweiten Projekter mit einem zweiten Bild,
um zeigen zu können, was die Regeln waren.
Ich habe hier im Kommentar von den Regeln aus dem Amerika
Scientific American einfach hier die Nummern geschrieben.
Was da schon drin stand in Regel 1 und 10 und 9
, gehen wir nochmal hier hin.
Jedes Haus eine andere Farbe, andere Nationalität,
anderes Lieblingsgetränk und so weiter
Im mittleren Haus wird Milch getrunken, das Regel 9
und 10 der Norweger lebt im ersten Haus von links.
Das können wir im Pro-Log schon mal so sagen.
Im ersten Haus von links wohnt der Norweger.
Hier steht die Hausrelation der Tierfest, den Norweger, ja?
So, und im mittleren Holz wird Milch getrunken,
da sagen wir die Hausrelation muss erfüllt sein,
in dem Haus hier an der mittleren Stelle Milch steht, ja?
Und die Variable Haar hat genau fünf Häuser,
das haben wir hier auch stehen. Damit ist schon mal
die Konstruktion erzeugt und diese weiteren Regeln, die sorgen jetzt dafür,
dass hier weitere Häuser erzeugt werden, die all diese Bedingungen erfüllen.
Das Haus vom Engländer ist rot. Der Spanier hat einen Hund,
das Haus von Spanier wohnt, da muss das Haus Türhund sein.
Das Haus, wo Kaffee getrunken wird, ist grün.
Das Haus, wo der Ukrainer erlebt, da ist das Getränk Tee.
Und das Haus, das Elfenbein farbene Haus ist rechts vom Grünenhaus.
Ja? Regel 6. Der Vincent Raucher hat Schnecken,
haben wir hier in dieser Regel. Cooles Haus ist gelb,
der Chest, der viel Traurer, ist da.
Das Haus mit dem Fuchs ist rechts von dem,
der Chest, der viel traucht und der Pferdehalt,
der Wund
Neben dem der Kult raucht und dann haben wir noch
den Lucky-Strike-Gerraucher mit Orangensaft und den Japaner der Pfalyamens raucht.
Norweger im blauen Haus und wir haben den Wassertrinker und den Zipra.
Das war unsere Frage hier. Ganz am Ende sagen wir,
gibt es jemanden, der Wasser trinkt und Zebra raucht,
wenn all diese Bedingungen erfüllt sind und damit erzwingen wir,
dass in diese fünf Häuser auch noch ein Feld reinkommt,
wo Wasser getrunken wird und Zebra steht.
Und die Lösung, die wir rauskriegen, ist,
man glaubt es kaum eindeutig, wenn wir danach fragen,
Zipra, Hauses, Wort der Drinker Zipra ohne.
Wir kriegen hier diese fünf Häuser und hier sind die,
ist die Lösung drin, ja? Was wir das nächste
Mal machen werden, das mache ich heute jetzt nicht mehr.
Da werden die Details vergessen worden sein. Nach demselben Schema
können wir aus dem ersten Harry Potter Band der Stein der
Weisen das Rätsel lösen. Was in welcher Zaubertrankflasche steht,
steckt an Getränken und was man sicher trinken kann,
um den Stein der Weisen zu finden.
Aber das machen wir das nächste Mal.
Danke für die Aufmerksamkeit