Termin hat das letzte Mal ja damit begonnen, dass wir über kombinatorische Probleme gesprochen haben.
Und was sie in diesem Abschnitt eigentlich sehen sollten,
ist, wann braucht man Rekursionen wirklich?
Also wir haben Rekursionen aus verschiedenen Sichten eingeführt,
nämlich einmal, dass man es gerne nimmt,
wenn das Problem von sich aus schon rekursiv aussieht,
die Datenstrukturen rekursiv sind, dann fallen nahtlos eigentlich die rekursiven Algorithmen vom Himmel,
mit denen man diese rekursiven Datenstrukturen bearbeitet.
Eine weitere Klatte von Problemen ist allerdings, wenn wir kombinatorische Probleme haben.
Dass wir mit Benjamin Seppke das letzte Mal begonnen hat.
Denn da haben wir häufig die Situation,
dass man systematisch jedes gegen jeden probieren muss und die Zahl der,
gegen die man probieren muss, ist vorher nicht festgelegt.
Also solange wir kombinatorische Probleme haben und die Situation ist,
dass die Zahl der Elemente, um die es geht,
fest ist oder eine feste Obergrenze hat,
kann man eine imperativen Programmierstil einfach hingehen und so viel Vorschleifen
ineinander schachteln,
bis man für jedes Element
eine Lösung hat
Irgendwann reist einem vielleicht bei 100 Stück der Geduldsfaden.
Aber es gibt eben Situationen, wo wir nicht vorhersagen können,
wie oft wir in eine innere Schleife eintreten müssen.
Und das ist genau die Situation, wo dann Rekursionen hilft,
weil wir durch die Rekursion jedes Mal in eine neue Schleife
erzeugen können, in der wir suchen.
Und ich möchte heute aus dieser Klasse der Algorithmen,
wo wir kombinatorische Probleme mit Hilfe von Rekursionen lösen,
noch den absoluten Klassiker behandeln
Das Backtracking und die Suche. Wir brauchen das als Vorbereitung für das,
was danach kommt, wenn wir nämlich anfangen wollen, überzugehen.
Zum deklarativen Programmierstil Mithilfe von Relation, der brauchen wir als
einen Baustein. Die Suche. Diejenigen, die jetzt
schon pullerkören, wissen das. Und das heißt,
wir brauchen, wir geben uns jetzt in Richtung,
wo wir Bausteine als fertige Werkzeuge entwickeln,
die im Funktionalen Programmierstil realisieren und zeigen,
wie man
eine Kontrollabstraktion macht
Also dieser typische Ablauf,
der für eine bestimmte Art von Suchen und kombinatorischen Problemen sinnvoll ist,
dass wir den als einen Baustein isolieren,
ihn mit Funktionen parametrisieren und dann praktisch noch vor Weihnachten so alles zusammen haben,
dass wir uns in der Prolog-System bauen können.
Von den Beispielen zur Backtracking ist ein absolut der Klassiker, das Acht-Damm-Problem.
Ich gehe eigentlich davon aus, dass sie es kennen.
Das sind Vorlesungen wie Algorithmen, Datenstruktur, das behandelt wird,
sodass wir anhand dessen einfach sehen, das ist anders,
wenn wir es im funktionalen Programmierstil versuchen zu lösen als im Imperativen.
Und an diesem Beispiel,
wo ich nicht so sehr an die Details gehen werde,
wie gesagt, weil ich gehe davon aus,
dass dir das Problem eigentlich schon kennen und dass wir uns nicht jede Kurzzeile anschauen müssen in der Lösung,
machen wir denn ein allgemeines Backtracking-Schemen,
also dass wir für eine späteren Probleme einfach fertig den Baustein in der Hand haben,
wenn wir Backtracking brauchen.
Und dann ist es egal, ob es im Ziege Kohlkopf und Wolf
geht oder ob es um Missionare auf der Flucht geht oder,
oder wir haben einmal das Backtracking selbst als Werkzeug und stecken nur Funktionen rein,
für das Problem typisch sind, ja.
Also Backtracking ist ein typischerweise rekursiver Algorithmen und wir wenden sie immer dann an,
wenn wir etwas durch Systematisches Programm probieren, rauskriegen wollen, ja.
Und wenn die systematische Probieren darin besteht, dass es in
jedem Schritt wieder das Problem ähnlich dem vorherigen aussieht.
Also man probiert immer einen kleinen Teil und das Restproblem,
was übrig bleibt, ist ein Tick kleiner.
Wir haben schon etwas erledigt, auch von der Struktur her,
ist es wieder genauso wie vorher, ja.
Und typischerweise führt dieses Rekord, die wir probieren dazu,
dass der Suchraum exponentiell anwächst.
Und das müssen wir noch sehen, wie wir damit umgehen können.
Aber jeder Probierschritt sollte dem vorherigen, strukturell ähnlich sein.
Also absolut der Klassiker beim Probieren ist, wir laufen durch ein Labyrinth.
Und immer, wenn wir voraus einen Schritt weiter gehen,
an der nächsten Kreuzung, haben wir wieder drei oder vier Möglichkeiten,
die wir untersuchen müssen.
Wir laufen in eine Richtung und stehen schon wieder von der
Verzweigung mit mehreren Möglichkeiten. Und aus den vielen Möglichkeiten,
die wir ausprobieren müssen, da müssen wir die Übersicht behalten,
dass wir alles absuchen,
bis wir
eine Lösung gefunden haben
Und diese Art von Suche ist eben auch ganz wichtig in Pro-Look,
dass diejenigen, die Pro-Look schon programmieren können, wissen das. Gut,
also ein typisches Beispiel, der Weg aus dem Labyrinth,
wie eben besprochen, oder wenn wir eine Landkarte haben mit Straßen und Wegen,
das für die kürzeste Verbindung zwischen zwei Städten suchen,
oder das Netz der Deutschen Bahn, wir wollen von Hamburg nach Lübeck,
man könnte einen Umweg über Freiburg fahren,
ist eventuell nicht der kürzeste.
Ja, oder Landkarte färben,
typische vier Farbenprobleme
Rätsel, wie kriege ich einen Wolf und Kohl,
Kopf und Ziegel in einem Boot über dem Flüss,
sodass keiner den anderen frisst, wenn immer nur zwei Teile auf einmal reingehören.
Wolf und Kohlkopf fahren friedlich zusammen, aber Wolf und Ziegel
nicht und Kohlkopf und Ziegel nicht. Und wir wollen alle rüberbringen. Okay,
magische Quadrate oder Krypti-Arrathmetik, ja, dass wir Textaufgaben haben,
wo jeder Buchstabe für eine Ziffer steht,
man soll so mit einer Ziffer füllen, dass die Summe hier aufgeht.
Das ist auch damit Problem. Also stellen Sie sich ein Schaffbrett vor und in der ursprünglichen Form,
wie dieses Problem pastuliert wurde, war die Frage,
wenn es mir gelingt, alle meine acht Bauern,
die ich habe, in Damen zu verwandeln,
wie stelle ich sie aufs Schachbrett,
sodass ich sie möglichst gut nutzen kann.
Und es ist optimal, wenn wir die Damen so aufstellen,
dass jede andere Felder auf dem Schachbrett bedroht und sie eben nicht verschwenden,
indem die Damen sich gegenseitig bedrohen.
Also, und zur Erinnerung,
wenn wir eine Dame auf Schachbrett stellen,
sie bedroht eine andere Dame, wenn sie derselben Zeile steht,
wenn sie derselben Spalte steht oder auf derselben Diagonalen
Also hier ist zum Beispiel eine Lösung. Es gibt tatsächlich eine.
Hier stehen unsere Damen auf dem Schachtbrett und in ihrer Dioriginalen
steht keine andere Dame, in der hier auch nicht.
In der Zeile, in der Spalte steht keiner, in der Zeile steht keiner.
Und für jede der Damen, die platziert sind, gilt das.
So, wie findet man so eine Lösung?
Mit dem Computer ist es einfacher. Der rekursive Ansatz,
der sagt sofort, verallgemeinern wir Es ist meistens erstaunlich so,
dass man immer für eine bestimmte Größe etwas rekursiv schreiben will,
dass die Funktion schwieriger werden, als wenn man sagt,
ich halte die Größe Schachbrett ist offen,
wir nehmen ein N mal N-Brett.
Das einzige, was wir fordern, ist, dass es quadratisch ist.
Wir haben das Problem gelöst, wenn in der ersten Zeile
eine Dame steht und dann eine Lösung für die restlichen N-minus-1-Zeilen gefunden wird.
Und wenn es keine weiteren Möglichkeiten gibt,
wir fangen an mit der ersten Zeile zu probieren,
stellen in die nächste Zeile und so weiter.
Und wenn wir dann in eine Zeile kommen und feststellen,
hier kriegen wir keine Dame mehr hingestellt dass sie von den vorherigen,
positionierten Damen bedroht wird, dann müssen wir zurückgehen.
Und die Zeile, die Dame in der Zeile davor verschieben und sehen,
ob wir dann in die vierte Zeile jemanden stellen können.
Wenn wir selbst nach zurückgehen,
keine Dame mehr positionieren können und das Brett ist doch nicht gefüllt,
dann gibt es keine Lösung und fertig.
Aber dasselbe Schema werden wir sinngemäß auf weitere Zeilen anwenden. Gut,
für den ersten Ansatz, ich habe dir keine Mühen geschult,
bescheuert, ihn herrliches Schachtbrett Ostmarmor und Melachit gebracht.
So, und da müssen jetzt die Damen drauf.
Also in jeder Zeilen, jede Spalte wollen wir nur eine Dame stellen.
Wenn wir da jetzt ein paar Damen positioniert haben,
dann kann eben die Situation kommen, also die bedroht das,
die bedroht das, die bedroht dies, das hier ist gesperrt.
Alles, was hier blau ausgekreuzt ist, sind bedrohte Felder.
Das heißt, so wie es hier im Moment ist,
können wir in Reihe 5 überhaupt keine weitere Dame platzieren.
Egal wo wir die hinstellen, sie ist bedroht durch andere.
Und deshalb müssen wir jetzt da etwas verschieben und so weiter
und so weiter und so weiter.
Verschieben, verschieben, verschieben. Zum Schluss müssen wir in Reihe
nur ein Zucker der Dame verschieben. Sowie suchen wir systematisch nach so einer Lösung,
also indem wir es mit der Datenstruktur einführen,
zum Beispiel ein Rekord, einfach Damen, Koordinaten, Queen-Koord,
es hat nur zwei Felder, Zeile und Spalte, Roe and Colum, ja.
Und wir können schon von der Aufgabenstellung her sagen, Mensch,
da jede Dame alles bedroht, was in derselben Zeile steht,
brauchen wir für jede Zeile nur eine einzige Position.
Da können wir nur eine Dame reinstellen. Und deshalb können
wir das Schachbrett mit seiner Belegung beschreiben durch eine Liste,
in der wir für jede Zeile sagen, wo eine Dame steht.
Und da kommt eben so ein Structure dahin. Also dadurch,
dass wir das definiert haben, haben wir jetzt auch Queen-Co-Ort-Roe
als Accessor-Funktion für die Zeile und für die Accessor-Funktion für die Spalte.
Und das ist der Konstruktor, einfach der Name dieses Typs. So,
dann brauchen wir noch eine Printfunktion, weil normalerweise werden sie gemerkt haben,
wenn sie so ein Structure erzeugen,
dann wird einfach der, wenn es gedruckt wird,
sie das kriegen wir nur irgendwie einen Schlüssel und keine Werte.
Also machen wir noch einen Defined Print Queen-Coord und das macht einfach
ein Display und gibt uns die Liste aus und sagt,
wo die Dame steht. So, als Resultat wollen wir zurückkriegen,
wie oft haben wir probiert, bis die Dame stammt,
ja, und das Resultat, wo drin steht,
wo die Damen jetzt stehen und so weiter.
So. Und dann definieren noch eine Funktion, die uns sagt,
sind wir fertig, die heißt Successful.
Und wie macht sie das? Die testet einfach,
ob diese Liste der Resultatposition nicht leer ist.
Ja. Gut. So wie suchen wir und testen wir.
Also die Hilfestellung, die man sich überlegen kann, ist,
wenn wir wissen wollen, ob eine Dame eine andere bedroht,
dann bedroht sie sie.
Weil, also entweder steht sie in derselben Zeile oder in derselben Spalte,
brauchen wir nur die Zeilen und Spaltenkoordinaten zu vergleichen.
Das ist einfach. Und bei den Diagonalen ist es,
dann halt zurück, die Dioriginale in diese Richtung,
da sieht man, wenn ich eine Zeile weitergehe,
ich auch eine Spalte weiter.
Das heißt, entlang einer diagonalen ist die Differenz aus Zeilen und Spaltenkoordinaten immer konstant.
Für diese Art von Diagonalen. Und bei der anderen Art von Diagonalen,
da ist die Summe konstant, weil wenn wir eine Zeile weitergehen,
die Zeile einen höher, ist es der für die Spalte, um einen kleiner.
Wir brauchen also, um zu testen,
ob zwei Dammen sich entlang der diagonalen Bedrohungen immer nur testen,
ob die Summe der Spaltenkoordinaten dieselbe ist oder die Differenz der Spaltenkoordinaten
Also eine Funktion, die testet, ob unsere Dame warm
und trocken steht, da wo wir sie hingestellt haben.
Da übergeben wir die Position und die neue Position, die wir testen wollen.
Und diese neue Position müssen wir mit allen schon besetzten Positionen vergleichen.
Und das machen wir jetzt schön mit Funktionen höherer Ordnung,
ein Endmap. Das gilt über die gesamte Liste der bekannten
Positionen. Und für jedes Element da testet es,
ist, ob die neue Position,
die haben wir mit Curry gebunden an die Funktion,
die die Funktion Check testet, aufruft.
Und zwar das Gegenteil von Check. Die Funktion höherer Ordnung,
die geht, macht aus einer Funktion aus einem Prädikat,
eins, was das Gegenteil zurückgibt im Wert.
Und wir binden es fest an die neue Position mit Currying.
Und das schicken wir einfach mit Endmap über die gesamte Liste.
Also lässt sich sehr gut mit Funktionen höhere Ordnung machen.
Und das Check, die Funktion können wir hier jetzt nochmal vollständig hinschreiben.
Wir müssen einfach erstmal testen, ob die Spalten gleich sind.
C1 gleich C2. Ob die Summe austeile und spalte,
dieselbe ist, damit testen wir die eine Diagonale.
Und für die andere Diagonale testen wir,
ob die Differenzen gleich sind,
für die erste Spalte
Zeile und die Spalte der ersten da mit Zeilespalte der zweiten Dame.
Wir testen nicht, ob die Zeilen identisch sind,
brauchen wir nicht, weil wir uns sicher sind,
dass wir in jede Zeile von vornherein nur eine Dame reinstellen, ja.
So, und damit haben wir unseren alles vorbereitet,
um jetzt rekursiv zu testen, ob wir,
wo wir Damen hinstellen wollen.
Also unsere Funktion try Queen, die wird rekursiv aufgerufen,
um in den Zeilen drauf immer Damen zu platzieren und
das kriegt sie als Parameter mit
Die Größe der Schachbretts, die Positionen, die wir schon haben,
die Zeile, in der wir jetzt eine Dame reinstellen wollen.
Die Spalte, wo sie testen, ob sie da stehen kann.
Und hier zählen wir einfach noch mit,
wie oft wir schon versucht haben, eine Dame zu positionieren.
Dann versuchen wir hier, eine neue Position zu erzeugen.
Ja, Roe and Colum. Das ist das,
wo wir jetzt testen wollen. Und dann fragen wir,
ist die Zeile, in die wir die Dame jetzt stellen wollen,
größer als die Größe der Schachbrett, dann sind wir fertig.
Also wenn wir dahin gekommen sind,
dass wir beim Schachbrett 8 mal 8 die neunte Zeile in der Dame stellen wollen,
sind wir fertig, weil wir wissen,
die vorherige Lösung ist in Ordnung.
Und dann können wir zeigen, wo wir das Schachbrett an mit Showboard.
Ja, da gibt es ein vordefinierte Funktionen in Recket,
die das macht. Wir erzeugen unser Resultat,
wo wir zurückgeben, so viele Züge hatten wir und die Positionen,
wobei wir es hingestellt haben. So,
wenn wir hier die Dame übers Schachbrett verschieben und schießen über den rechten Rand raus,
dann sehen wir, oje,
in dieser Zeile haben wir nirgendwo eine Stelle gefunden,
wo wir sie hinstellen können.
Und dann müssen wir
mit dem Backtracking beginnen
Ja, also in dem Fall, wo wir rechts drüber geschossen sind,
da geben wir als Resultat leere Liste zurück und sagen falsch.
Jetzt sind wir aber auf dem Schachbrett,
nicht außerhalb der Zeilen, nicht außerhalb der Spalten.
Jetzt müssen wir testen, ob die Dame an der Stelle,
wo wir sie hingestellt haben, war, man trocken steht.
Und wenn sie nicht sicher steht, dann zeigen wir an,
wo es gerade zur Zeit aussieht und versuchen jetzt
die Dame in die nächste Spalte zu stellen.
Hier rufen wir uns rekursiv wieder auf, Größe,
das Schachbrett bleibt gleich, wir machen sich heimlich zwischendrin kleiner oder größer.
Die Positionen, die wir hatten, sind dieselben geblieben.
Ja, es war ja eben erfolglos,
wir bleiben in derselben Zeile und gehen eine Spalte weiter
Und wenn das eben auch nicht geklappt hat und die Dame sicher ist,
dann versuchen wir in der nächsten Zeile einen unterzubringen.
Hier gehen wir jetzt in die nächste Zeile und rufen da,
dass drei Queen wieder auf.
Und wenn wir das geschafft haben, dann sind wir fertig.
Das sieht eigentlich ziemlich kompliziert aus. Und das ist so kompliziert aussieht,
liegt daran, dass wir nach genau einer Lösung suchen.
Also wir werden feststellen, es ist deutlich,
meistens deutlich einfacher. Man sucht einfach systematisch alle Lösungen.
Und bei der ersten, die man findet,
sagt man purar
Also jetzt versuchen wir es mal. Queen, wann,
drei Queen,
berufen wir auf mit irgendeiner Größe und dann an der Stelle 1
zu 1. Also jetzt mal speziell für das Schachbrett der Größe 8,
da sehen wir, dass wir ziemlich viele Züge gebraucht haben,
um das zu finden.
Und wir haben dann die erste Position gefunden,
wo es klappt. Selbst beim kleinen Schachbrett,
4 mal 4, da brauchen wir schon 53 Züge,
um die eine Lösung zu finden,
die es gibt.
Die zweite hier ist spiegelbildlicher
Okay. Der Show Queen ist ein Fuhr definierte Funktionen,
die wir in Recket haben. Und der übergeben wir einfach
ein Schachbrett. Es besteht aus einer Liste von Listen.
Jede Liste sagt für die Zeile, ob da eine Dame steht oder nicht.
Und das Show Queen zum Beispiel, da sehen wir dann,
hier steht eine Dame da, da und da.
Das ist eine der Lösungen, die wir fürs Viererschachbrett kriegen können.
Und das ist ganz neckisch, wenn man es damit anzeigt,
kann man auf irgendein Feld gehen und man sieht dann,
so ist es hier angezeigt,
welche Dammen dieses Feld bedrohen und welche nicht
So, machen wir mal den Ablauf, das Backtracking für die Vierer-Damen, ja?
Wenn wir alle Lösungen suchen, versprechen, wird es einfacher.
Wir ändern das jetzt einfach so, dass jeder rekursive Aufruf
von Schreibqueen eine Liste von allen gefundenen Lösungen zurückgibt.
Und die Listen werden mit Apension der Gesamtliste verbunden. Und um alle Lösungen zu finden,
da probieren wir nicht immer ein Verschieben entlang der Zeile,
sondern rufen drei Queen einfach auf, für jedes Feld,
für jede Spalte in der Zeile, wo wir gerade sind,
und die verbinden wir.
Wenn Sie positiv sind, wenn die Resultate positiv sind,
nehmen wir Sie, wenn Sie nicht positiv sind, vergessen wir Sie.
Und das können wir dann mit Map machen. Also drei
All Quinns, wie der größte Schachbrett, die Position,
die wir bisher besetzt haben in den Zeilen davor.
Die Zeile, die wir gerade untersuchen wollen, die Spalte,
wo wir testen wollen, darf es da stehen.
Wieder müssen wir fragen, ob es nicht sicher ist,
dann sagen wir, leere Liste kommt zurück.
Wenn wir in der letzten Zeile sind, dann haben wir
alles platziert und geben die Lösung zurück. Und in allen anderen Fällen Da geben wir dann einfach zurück,
er pennt, wir machen ein Mapping,
wo wir ein Currying machen von Try All Queens und hier dann entweder,
das ist ein bisschen albern,
aber ich habe es nie elegant da hingekriegt, Ruh gleich null,
dann geben wir die leere Liste für den Fall,
dass wir an der Abbruchstelle sind,
in allen anderen Fällen machen wir einen Kunst von Positions to 3,
an die Positionen,
die wir schon haben.
Also hier haben wir Füro gleich null als Resultat,
die leere Liste und sagen dann über die nächste Zeile und zwar für alle Spalten
Von 1 bis N. Ja, der natürlichen Zahlen von 1 bis 1.
Und dann sind wir fertig. Einfach in der Rekursion,
statt da jetzt in die Baumrekursion abzusteigen,
indem wir für jedes Balde separat aufrufen,
machen wir einfach ein Mapping von der Versuchsfunktion über die Liste aller denkbaren Spalten.
Also hier gehen wir über die natürlichen Zahlen von 1 bis Size und fertig.
Und dann können wir es also aufrufen und sehen,
wir kriegen eine Sage und schreibe 92 verschiedene Lösungen für
ein Schachbrett der Größe
Also die ersten hier mal aufgeschrieben, indem wir sie uns anzeigen lassen.
Viele sind strukturell ähnlich und man kann das Schachbrett ja dreimal
um sich selbst um 90 Grad drehen und dann findet man
jedes Mal wieder eine neue Lösung, weil das Bedrohen symmetrisch ist.
Das Interessante ist, wenn man diese, eine Lösung Ansatz hat,
dann sieht man dem nicht mehr an, dass es ein Backtracking ist.
Das heißt deshalb auch Erfolgslistenverfahren, weil wir einfach sagen,
versuche, versuche, versuche neben die,
wo es geklappt hat,
man macht nicht mehr explizit
ein Backtracking
Sondern von vornherein ab der ersten Zeile probiert man systematisch alles durch.
Okay. Generator, lassen wir mal außen vor.
Was jetzt mir wichtig ist an diesem Beispiel, ist,
wie machen wir uns jetzt für alle denkbaren Backtacking-Probleme ein einziges Werkzeug,
das Respekttracking für uns erledigt.
Dass wir nicht mehr drüber nachdenken müssen,
wie gehe ich zurück oder wie mache ich diese Erfolgslistenansatz,
sondern wir haben eine Kontrollstruktur, die macht ein Backtracking und fertig.
Und dazu brauchen wir eine Beschreibung der Probleme, möglichst funktional.
Und wir nehmen dann jeweils eine Beschreibung des Problems und sagen,
und für diese Problembeschreibung macht mir das Backtracking.
Die Problembeschreibung können wir uns so vorstellen, wir wollen eine Backtracking,
alle Probleme lösen, wo man systematisch probiert, mit einem Staatszustand beginnt.
Und in jedem Schritt gibt es nur wenige mögliche Folgezustände.
Also wenn wir uns jeder Schachzeit vorstellen, hätten wir jetzt
acht Möglichkeiten, die Dame in die erste Zeile zu stellen.
Und wenn wir eine Dame irgendwo hingestellt haben,
aber in der nächsten Zeile wieder acht Möglichkeiten,
sie irgendwo hinzustellen, Die Folgezustände sind strukturell immer gleich aus.
Ja, es wächst hier exponentiell,
weil wir in jedem Zustand viele Möglichkeiten haben zu probieren.
Und für ein allgemeines Schema überlegen wir uns jetzt eine
Darstellung für einen Zustand, den wir übergeben können.
Und wir brauchen eine Funktion, die bei einer gegebenen Datenstruktur
für den Zustand uns die endliche Zahl der sinnvollen Folgezustände,
in diesem einen Zustand erzeugt.
Ja, es hängt vom Typ des Zustands ab,
was man hier so macht. Wir gehen davon aus,
dass der Rahmen, dass der generisch ist,
wir können für irgendeinen Zustandsdatentyp Einfach dann eine Funktion übergeben,
die für diesen Datentyp die Folgezustände erzeugt.
Und dann brauchen wir noch etwas, das erkennt,
ob wir hier als Zielzustand haben, der Test, ob es richtig ist.
Und wir brauchen noch einen Test, der testet,
ob das, was wir hier als Folgezustände erzeugt haben,
ob das zulässig ist oder nicht. Also beim Schachbrett,
Dame auf dem Schachbrett, wäre die Frage,
es ist zulässig, wenn wir,
wenn die Dame da sicher steht und eine andere bedroht sie,
wäre unzulässig, wenn sie da eben bedroht ist.
Ja,
auch das hängt jetzt vom Datentyp des Zustands ab
Was man da macht. Und wir sehen einfach für den Zustandstyp,
den wir im Augenblick haben, vor,
dass es eine Funktion gibt, die testet, ob es zulässig ist.
Und damit sind wir eigentlich fertig. Also wir repräsentieren den Zuraum
als Menge von Zuständen. Das sind Listen von Positionen,
von Damen, Koordinaten im Labyrinth, wo wir gerade stehen oder so, ja.
Wir haben einen Ausgangszustand, mit dem wir loslegen.
Das könnte beim Acht-Dame-Problem das leere Schachbrett sein. Dann haben wir
eine Generatorfunktion. Wenn wir irgendwo sind in unserer Suche,
generiert es uns alle Positionen in der nächsten Schachbarzeile oder die
nächsten Schritte im Labyrinth
Dann prüfen wir, ob der Zustand zulässig ist.
Beim Labyrinth wäre es zum Beispiel unzulässig, dass man einfach
durch die Mauer sich ein Loch haut oder so.
Und dann haben wir noch den Test, das auf Erfolg,
also Schachbrett ist voll und wir hatten zwischendrin keine Klagen.
Wenn wir das Backdrecken als Funktionen höherer Ordnung mal so schreiben wollen,
dann schreiben wir jetzt eine Funktion General Backdrecking und die hat vier Parameter.
Erste ist der Ausgangszustand, haben einfach einen Parameter Ausgangszustand,
da können wir was übergeben. Dann haben wir eine Funktion,
die bekommt einen Zustand und liefert eine Liste von Zuständen.
Die gibt uns genau, wenn wir hier stehen,
Zum Beispiel hier, dass der Zuständige übergeben, kriegen wir diese beiden.
Den und den. Oder wenn wir hier stehen, kriegen
wir diese beiden. Also eine solche Funktion übergeben wir,
definiert für einen Zustand als Eingabe und Liste von Zuständen als Ausgabe.
Test auf Zulässigkeit, das ist ein Prädikat, eine Funktion,
die guckt sich den Zustand an und sagt, unzulässig,
du bist durch die Mauer im Labyrinth gelaufen.
Und einen Test auf Erfolg, den übergeben wir,
der sagt, ja, prima Schachbrett ist gefüllt.
Oder du hast den Schatz gefunden in der Mitte vom Labyrinth.
Diese Funktion taufen wir, ist Legal,
die bildet vom Zustand auf den Wahrheitswert ab oder Endzustand,
bildet vom Zustand auf den Wahrheitswert ab
Genau. Und das schicke Ding passt auf eine Folie.
Also diese nette, kleine Helfer hier wird Ihnen in Zukunft
jedes Backtracking-Problem lösen. Einfach das Schimmer einprägen und anwenden.
Also wir taufen, ist Venderal Backtracking, übergeben den Ausgangszustand.
Die Funktion, die einen Zustand nimmt, Folgezustände erzeugt.
Die Funktion, die testet, ob der Zustand
gut ist und ob sie fertig ist.
Und diese Variante, die findet alle möglichen Lösungen.
Kleine Warnung kann in eine Endlosschleife gehen
Wenn unter welcher Bedingung kannst du in der Entschlusssteife gehen?
Zum Beispiel im Labyrinth,
wenn wir immer wieder im Kreis laufen und keine Abbruchbedingungen haben.
Also wenn der Baum sich nach unten unendlich expandieren kann,
da muss uns noch was einfallen.
Wir gehen jetzt erstmal davon aus, dass der Raum,
den wir absuchen, endlich ist, der Sucher.
Was macht es? General Backtracking. Das versucht es.
Deshalb heißt die Funktion hier drei. Und die bekommt
einen Zustand. Und wenn der Zustand nicht zulässig ist,
hier wird es die Funktion,
ist Legal aufgerufen,
die wir
hier übergeben haben
Denn geben wir einfach zurück Fail mit dem Zustand,
haben wir kein Glück gehabt. Wenn es der Endzustand ist,
über die Funktion ist Final aufgerufen,
dann binden wir diesen Zustand mit Cons an die Liste aller Weiteren.
Lösung. Und die suchen wir mit Appentmap,
indem wir drei anwenden, auf alle Folgezustände des Zustands,
in dem wir gerade sind.
Wir rufen hier den General neue Zustände auf.
Also da regents steht es, wenn wir hier sind,
jetzt diese beiden aufrufen und dann mit dem weitermachen
Trial Gens, die jetzt für den Folgezustand.
Und was da in Lösungen zurückkommt, wird mit Appentmap verbunden.
Ein Mapping und das Mapping liefert uns Listen und diese Listen verbinden wir mit Appent.
Das macht Appentmap. So, wenn es kein Endzustand war,
dann müssen wir ihn nicht mit Cons an unsere Resultate ranbinden,
sondern wir sagen hier einfach nur Appentmap 3 und gehe über alle Folgezustände.
Und dann müssen wir das Ganze noch für den Anfangszustand aufrufen.
Das passt hier gerade eben noch. Und wir sind fertig
. Also das allgemeine Backtracking-Schema, wenn es uns gelingt,
unser Problem auf eine Zustandsraumbesuche abzubilden, ist relativ simpel.
Kleine Funktionen, höhere Ordnung mit Ausgangszustand, zwei Funktionen,
die drei Funktionen, die wir übergeben. Okay,
wir können das jetzt mal an einem ganz simplen Beispiel machen,
wo man eigentlich suchen müsste, nur um zu sehen, wie man parametrisiert.
Also wir wollen beginnen mit einer natürlichen Zahl und sehen,
ob wir durch Addition eine andere bestimmte finden können.
Wissen wir, dass es so ist? Müssen wir eigentlich nicht suchen,
aber wir bilden es mal auf dieses Problem ab,
einfach um es sehen zu können.
Ausgangszustand, irgendeine natürliche Zahl End Null,
Folgezustände ist nur die Menge mit dem Nachfolger NPlus 1,
zulässig ist es, wenn ein kleiner ist,
als diese NZ, was versuchen.
Und Erfolg haben wir, wenn das ein Gleich der gesuchten Zahl ist.
Könnten wir also so schreiben, die feinen Count,
wir rufen General Backtracking auf, stattzustimmt.
Dann die Liste der Folgezuständen besteht nur der Rollenbesitz im Zustand eins addieren.
Ja, ein bisschen langweilig. Ob der Zustand zulässig ist,
da fragen wir, ob unser Zustand kleiner gleich als im Endzustand ist,
dass unser, ist Legal?
Und der Test, ob wir angekommen sind,
Wir testen mit Equals, ob der Zustand gleich unserem Ziel ist.
Ja, und dazu binden wir Curry mit Curry in das Equal an den Endzustand.
Ja, jetzt rufen wir mal unser Count auf,
1,3 und wir kriegen zurück 1,3, kein weiterer Zustand mehr und 4 sind wir fertig.
Okay, das sind schöne Protokoll hier, was mit rausgekommen ist.
Ich hatte da heimlich noch ein Protokoll mit eingebaut, einen Aufruf an Schreien. Und wir sehen die lineare Rekursion. Wir hätten es auch anders schreiben können,
indem wir Noch mehr Funktionen höherer Ordnung verwenden,
zum Beispiel Ausgangszustand, sei es immer eins,
wir können List an Advann binden mit Compost,
dann haben wir die zusammengesetzte Funktion übergeben, sagen,
ob es ist, Legal ist immer wahr, wir wissen eigentlich,
dadurch, dass wir immer nur eins drauf addieren, es ist zulässig,
also können wir die Funktionen Olvis True übergeben und das Gleich-N-Zustand gleich-N,
wie machen wir Currying an N, wir sehen schon,
man muss hier eigentlich gar keine Hilfsfunktionen definieren,
sondern kann sie alle mit Funktionen höherer Ordnung zusammenbauen
Gut, jetzt das Acht-Damen-Problem als allgemeines Back-Tracking-Problem. Zustand über
Liste von Koordinatenpaaren. Position is safe, die prüft eben,
ob mithilfe der Funktion checkt, ob das stimmt.
Und das Brett ist gefüllt, wenn so viele Damen stehen
auf dem Brett, wie das Brett, Seitenlänge hat.
Längs steht gleich sei es. Also würden wir
das Acht-Damen-Problem mit unserem General Back-Track im Kontrollrahmen so schreiben,
dass wir ein General Back-Tracking machen,
Ausgangszustand ist gar keine Dame,
steht auf dem Brett
Wir übergeben Lust auf Next Positions. Das ist die Funktion
, die uns in Folgezustand gibt. Die Funktionen,
die testet, position is safe und alle Zeilen gefüllt.
Die können wir hier mit Komfunktionskompositionen und Currying gleichseits im Vergleich mit der Länge machen.
Und dann sind wir fertig. Okay. Also unser allgemeines Backtracking-Schema,
wir brauchen den Suchraum repräsentiert, wir brauchen den Ausgangszustand,
die Generatorfunktion, Test auf Zulässigkeit und Test auf Erfolg.
Und da können wir jetzt mal ein anderes Beispiel machen,
was ich gar gerne verwende, weil es ihnen zeigt,
dass es auch geht, wenn das Problem nicht ganz so metrisch ist.
Also das ist so eine Knobel-Logik-Rätsel, was wir irgendwann mal
im Radio gehört haben und dann habe ich gedacht,
ach ja, das probieren wir mal.
Die Situation ist die folgende, wie bei den meisten Logik-Rätseln,
ist es eine total unwahrscheinliche Situation, die sehr konstruiert wirkt,
aber egal, sie bringt trotzdem Spaß.
Also wir stellen uns jetzt vor, vier Missionare sind unterwegs,
wo immer sie missionieren wollen und stehen an einer Brücke über eine tiefe Schlucht.
Ja, und jetzt beginnen die Unwahrscheinlichkeiten. Zum einen,
die waren noch nie da,
aber jeder von ihnen weiß genau, wie lange er braucht,
um über diese Brücke
zu gehen
Also einer braucht 25 Minuten, einer 20,
einer 10 und einer 5. Das wissen sie schon.
Ja, woher auch immer. Zweite ist, die Brücke ist unglaublich baufällig.
Wenn man da drüber geht, muss man eine Lampe dabei haben,
um gut sehen zu können, weil es ist Nacht.
So, und im Hintergrund lauern wilde Tiere.
Und die Missionare sind hochmotiviert,
da drüber zu gehen und was sie jetzt auch wissen,
das ist das, was sie absolut nicht mehr glaube.
Sie haben eine Taschenlampe dabei und von der wissen sie,
dass ihre Batterie noch exakt eine Stunde hält.
Ja, also Vorwissen, Batterie,
der Taschenlampe hält noch
genau eine Stunde
Jeder von ihren Vieren weiß, wie lange er braucht, rüberzugehen.
Und jetzt haben wir noch die Einschränkung. Die Brücke ist
so baufällig, dass nur zwei Missionare gleichzeitig draufgehen können.
Also das ist eigentlich die Regel für alle Hängebrücken,
die man so in der Welt findet,
steht immer eine zwei Personen gleichzeitig drauf.
Also zwei müssen gleichzeitig rübergehen und sie haben nur eine Taschenlampe.
Und eine muss auch immer zurückgängen und den anderen dann netterweise,
die ist ja schon Lampe noch bringen.
Ja. Die fünftere Nacht so. Okay. Mach
mal weiter hier
Ja. Guchen, also Missionare in der baufälligen Hängebrücke,
trägt nur zwei Personen, stockfinstere Nacht, Taschenlampe, die nur eine Stunde brennt.
Und sie brauchen fünf Minuten, zehn Minuten, 25. Und sie wollen alle rüberkommen. Jetzt ist es ein gutes Beispiel,
wo man einfach probieren kann, man schickt mal so zwei zusammen rüber,
zum Beispiel sagt man sich, okay,
weil ja über die Taschenlampe zurückkommen muss, nehmen wir den fünf Minuten Menschen,
der es in fünf Minuten schafft, der weiß,
ob das beim vierten war auch nur an fünf Minuten schafft,
aber egal.
Der bringt immer einen nach dem anderen rüber und rennt dann
zurück, ne?
Das können wir mal ausprobieren
Ja. Das heißt, schauen wir uns mal an,
was passiert nach der Methode, der Schnellste rennt immer hin
und her und bringt einen Kollegen nach dem anderen rüber.
So, 5 und 25 gehen rüber. Jetzt hat Nummer
5 zurück mit der Als Fackel, holt die Nummer 20.
Wir haben noch 30 Minuten, das sieht man hier unten,
ja? Jetzt haben wir noch zehn Minuten.
Jetzt muss er zurückrennen, den zehn Minuten Menschen zu holen.
So, jetzt haben wir nur noch fünf Minuten.
Also das klappt leider nicht. Ja,
in der Mitte der Brücke ist die Stunde um Taschenlampe
aus und sie fallen
Unter die Krokodile, weil ich immer da gelauert habe.
Also die Methode, den schnellsten hin und her schicken zu lassen, das klappt nicht.
Und da muss man anfangen zu überlegen, ja Mensch,
was macht man dann? Also ich habe ein bisschen überlegt,
mir fiel keine Lösung ein, wenn ich mich daran erinnere,
dass ich pro Lockern und habe es dann im Prolog programmiert
und habe noch eine Lösung gefunden, gesucht.
Und dann ist die Frage, wie modelliert man es, ja?
Wir können das jetzt mit dem allgemeinen Backtracking machen.
Wir haben als Zustand für das Problem,
welche Missionare stehen links, welche missionarisch stehen rechts,
egal was sie missionieren wollen,
wir reduzieren sie und abstrahieren sie auf die Zeit,
die sie brauchen,
über die Brücke
zu gehen
Müssen wir in der Nahre heißen, also 2010,
5 von 25, dann musst du,
im Zustand müssen wir wissen, ist die Taschenlampe rechts oder links.
Ja. Und die Restzeit, die wir noch haben.
So, das ist der Zustand. Und die Übergangsfunktion,
wenn die Taschenlampe links ist, dann schicken wir zwei mit
der Taschenlampe nach rechts. Und wenn die Taschenlampe rechts ist,
schicken wir zwei Missionare mit der Taschenlampe nach links.
Ja. Es ist zulässig, wenn die Restzeit noch positiv ist.
Wir sind fertig, wenn keiner mehr links steht.
Also links ist die Liste leer. Und dann führen wir
noch ein Protokoll ein, was die Zustände führt.
Das gehe ich mal, wie man das macht
Also, wir definieren unsere Missionare. Zustand ist die Liste der Geschwindigkeiten,
die Sie haben, ja, die übergeben wir die Liste 15,
20, 25 und die maximale Zeit eine Stunde.
Und dann habe ich noch eine Funktion Pretty Print Protocol geschrieben,
die schicken wir mit dem Map über die Liste der Protokolle.
Die vergessen wir jetzt mal. Das Backtracking. Das bekommt als Ausgangszustand
einen Aufruf der Funktion Mick Missionary Steed aus den Geschwindigkeiten,
damit zu Anfang stehen, alle vier Missionare Links,
ja, rechts steht keiner,
rechts ist die Liste leer
Die Taschenlampe ist auch links, sonst hätten sie gleich verloren.
Und die Max Tee ist die Zeit, die sie haben,
diese eine Stunde. Und das Protokoll hier ist leer.
Dann übergeben wir eine Funktion Generate Moves. Das soll eben die sein,
die die nach links oder rechts schickt, je nachdem.
Und dann ist dieses legal, es ist legal,
wenn größer gleich null gebunden, ja,
mit Curry und die Funktion größer gleich an null gebunden ist.
Und das muss gleich der Zeit seinen Scheiben left,
die wir haben, ja. So, und dann haben wir
noch ein die Funktionskomposition aus Null ist leer, die linke Gruppe.
Und dann haben wir, das gibt uns also die Frage,
es sind links jetzt alle weg, dann sind wir fertig.
So, und ganz am Ende geben wir einfach so Truth zurück.
Ja, Generate Moves, das ist jetzt unsymmetrisch.
Also wenn die Fackel, die Torps hier links ist,
dann berechnen wir alle Züge, um nach rechts zu gehen.
Und wenn sie rechts ist, berechnen wir alle Bezüge,
um von links nach rechts zu kommen.
Und jetzt lassen wir es mal laufen
Siehe da, es gibt tatsächlich eine Lösung. Wahrscheinlich sind sie
alle schon drauf gekommen, dass es genau die ist.
Das dicke Problem ist, die Zeit reicht nicht,
wenn die beiden langsamsten Schlappschwänze nacheinander über die Brücke gehen.
Der eine braucht 25, der andere 20. Und die einzige Chance,
um diese beiden sich herüberzubringen, ist,
dass man den Zwanziger gleichzeitig mit dem 25er laufen lässt.
Dann brauchen sie zusammen eine 25 Minuten.
Also ist die Lösung, ganz zu Anfang schicken wir die
beiden fixesten nach rechts
Den Fünfer oder den Zehner, der Fünfer rennt zurück,
bliebt die Taschenlampe vertrauensvoll, den beiden langsamen Opis, die wir haben.
So, und die laufen zusammen oder nicht laufen,
sondern krabbeln rüber und sind dann da.
Und dann läuft der Zehner zurück und holt seinen Fünf-Minuten-Kollegen ab.
Ja. Oder aber symmetrisch dazu. Im ersten Schritt läuft
der Zehner zurück. Wieder gehen die beiden langsamsten gemeinsam rüber und
dann kommt der Fünfer zurück und holt seinen Zehnerfreund ab.
Und dann haben sie genau eine Stunde gebraucht. Ja.
Okay. Also das eine Möglichkeit des General Backtracking dann,
was wir gelernt haben am Beispiel der Achtdam,
einfach mal so zu übertragen, offen unsymmetrisches Suchtproblem.
Das geht wunderbar, muss sie eben nur an die Struktur halten.
Eine gute Datenstruktur für den Suchraum, wo man in jedem
Schritt nur eine endliche, kurze Liste von Möglichkeiten hat.
Darauf wendet man, die werden erzeugt durch die Funktion,
erzeuge eben die Folgezustände. Da testet man,
ob es zulässig ist, ob es der Erfolg ist.
Dafür übergeben wir zwei Funktionen und damit ist alles gerettet.
Nur so zum Spaß, weil ich das einfach eine
schicke Alternative finde. Wir werden jetzt für einen kurzen Moment
wieder imperativ
Man kann diese kombinatorischen Probleme sehr gut nicht deterministisch lösen.
Also wenn die von einer innlichen Struktur sind,
können wir auch uns vorstellen, dass wir es einfach Parallelverarbeitung definieren,
indem wir in jedem Schritt, wo wir mehrere Möglichkeiten haben,
zu untersuchen, einfach nicht deterministisch eine davon ausprobieren.
Ja, wir generieren sämtliche Folgezustände und fragen einfach nicht
deterministischen Programmieren, führt eins davon zum Ziel.
Und dazu gibt es in Record den schönen Operator Amp
Und diese Amp-Operator ist ursprünglich von McCarsy in Lizb eingeführt worden.
Und dem übergibt man eine Menge von Möglichkeiten.
Und er merkt sich, was er schon ausprobiert hat.
Er will halt nicht deterministisch eine der Möglichkeiten aus,
tut es. Und wenn man dann feststellt, okay,
das war es nicht, dann weiß der Amp-Operator vom Aufruf,
den man vorher hatte, noch,
was die anderen Möglichkeiten wären und probiert sie automatisch selbst aus.
Also Amp macht, wenn das,
was er einem angeboten hat,
nicht geklappt hat und man sagt, nee,
war nichts,
geht er zurück und probiert automatisch
die anderen Möglichkeiten
Das ist also sehr praktisch, um ohne das zurückzugehen,
selbst programmieren zu müssen, einen klaren Ablauf zu haben.
Ja, ist, weil er so praktisch ist,
NJ League Operator genannt, fast gut in die Weihnachtszeit.
Ja, engelhafter Apparator, himmlisch. Wenn eine Lösung existiert,
man programmiert es richtig mit Emd, dann wird sie auch gefunden.
Ja, Emd verspricht, dass von allen Alternativen eben angeboten werden,
wenn dabei eine Lösung ist,
dann wird man die Lösung finden.
Ja,
außer man macht es falsch.
Also einfach nur mal zu sehen, wie es denn taktisch
geht, ja. Ich schreibe, also zum einen,
wir müssen jetzt in die Welt von Kommen lusprieren, ja.
Um M verwenden zu können, schreiben Sie bitte in Ihr Recket-Programm rein.
Require, Swindle, extra im Extra-Paket, ist dieses M versteckt.
So. Und ich sag dir mal, M,
die Möglichkeiten, die du testen solltest, wären 1,
2, 3, 4. Das hat jetzt nicht viel,
viel Sinn, aber einfach nur, um zu sehen,
wie es geht
Wenn ich ohne Argument aufrufe, dann sage ich dem M,
ey, das, was du mir angeboten hast, war nichts.
Damit erzwinge ich ein Fehl. Beim ersten Aufruf hat Empir
einfach nur eine Angst gegeben. Wenn ich ihr jetzt sage,
das war nichts, dann kriege ich als Resultat ihr zwei zurück.
Es steht automatisch die zwei als nächste Möglichkeit im Raum.
Wenn ich wieder sage, nee, die mag ich auch nicht,
ohne Argumente, einfach ein Fehl,
dann kriege ich die drei und dann kriege ich die vier.
Und wenn ich so unverschämt bin, alles abzulehnen und nochmal sage,
es war nichts, dann sagt Emptree Exosted und sagt,
es ist Fehl,
also keine der Möglichkeiten,
hat leider zum Erfolg geführt
Und das verwenden wir jetzt mal, um zu zeigen,
dass es das Amp, ein zustandsorientiertes Programmieren ist, also hochgradig imperativ.
Wenn ich den Wert von Amp an eine Variable binde,
die Fein AM und so weiters, und die fragt sich jetzt,
ab welchen Wert hast du, dann kriege ich die eins zurück.
Wenn ich sage, oh,
mit dem einen Wert hat es nicht geklappt,
ich frage jetzt meine Variable A ab,
welchen Wert hast du denn sehen, wird jetzt mal einmal dem Wert 2.
Der Zustand hat sich geändert. Und wenn ich es
nochmal verwerfe, hat A den Wert
Das heißt, das Amp gilt so weit zurück bis zum
letzten Aufruf. Und das, was dort definiert wurde,
wird neu definiert für die neuen Möglichkeiten. So, und
dafür jetzt, noch wie sammeln wir alle erfolgreichen Lösungen ein?
Wir können M verbinden mit einem Amp Assert, Amp Assert.
Das geht alle Möglichkeiten durch, die Amp gebraucht hat
und findet die heraus, die eine bestimmte Bedingung erfüllt.
Wenn meine Bedingung ist, dass A größer Vier ist,
dann kriege ich nach dem Aufruf von Amp Ah, Großjahr 4,
ja, nach dem Aufruf von End bekomme ich zurück,
dass A, den Wert 4 hat, vorher hat es den Wert 2 gehabt, ja.
Und das wird so lange durchprobiert, bis tatsächlich die Bedingung erfüllt ist.
Wir schauen uns das jetzt mal an ein Beispiel an,
mit dem man solches Programmieren richtig gut machen kann.
Das, was Emp-Sert durchlässt, können wir mit Emp-Collect
sammeln und das sammelt alle Lösungen ein.
Also wir sind wieder bei Swindle extra und ich sage hier Emp-Collect,
sammle mir mal alles ein,
was meine Zusicherungen erfüllt
Ich habe eine Variable A und eine Variable B. A
soll genommen werden aus der Liste der Zahlen 1 bis 7.
Wie soll aus der Liste der Zahlen 2 bis 8 kommen?
Und zwar nur die Graben. Und ich möchte nur die haben,
wo die Summe von A und B gleich 7 ist.
Ja. Und wenn das gut geht, dann mache ich
einen Kunst von A und B. Und das kommt zurück.
Was liefert das? Am Collect Mail hier? Das liefert mir
den Wert von A gleich 1 und B gleich 6,
den Wert von A gleich 3,
ich gehe gleich 4. Und den von 5,
gleich 5 und B gleich 2. Das sind die einzigen Paare von A und B,
die diese Bedingung erfüllen.
Statt zu suchen, Sag ich, also einfach,
deine Möglichkeiten für A sind das, deine Möglichkeiten für B sind das.
Und sie sollen diese Bedingung erfüllen und sammeln mir alle ein,
die diese Bedingungen erfüllen. Also er muss nicht probieren,
man muss nicht suchen, das läuft im Hintergrund,
wird einem das von dem End gemacht.
Das finde ich wirklich genial. Und ein etwas komplexeres Problem,
was wir damit mal jetzt wirklich lösen können,
zum Beispiel, das vier Farbenproblemen zu lösen.
Nicht beweisen, dass das lösbar ist,
sondern für eine gegebene Landkarte eine Lösung finden.
Können wir die Länder auf eine Landkarte mit nur vier Farben
so färben, das benachbarte Länder nie die gleiche Farbe haben
Und wir versuchen, durchsuchen jetzt nicht deterministisch mit Empf,
den Baum aller Möglichkeiten, die Farben auf die Länder
zu verteilen und sammeln dann nur die Landkarte ein,
die von Erfolg ist, ja.
Es ist, man kann es sich wieder als Zustandsraumsuche darstellen,
also hier mal, ich habe das,
um es darstellen zu können, auf ein Dreifarbenproblem reduziert.
Wir haben jetzt so die drei Farben blau,
rot und grün und wir beginnen mit einem Knoten,
wo wir als erstes die Möglichkeit hätten,
das Land eins in blau, grün oder rot zu farben.
So und wenn wir das haben,
dann Können wir das Lernen 2 nicht auch blau färben,
aber wir könnten es noch grün oder rot machen.
Und wenn wir das gemacht haben, können wir das Land 3
weder blau noch grün machen, sondern nur noch rot.
Das sind die Möglichkeiten. Oder hier hätten wir ähnliche Möglichkeiten ausgekreuzt.
Das ist alles, was nicht geht. Und das versucht
diesen Baumzustandsraum, versuchen wir jetzt mal mit Empf zu durchzuverlieren.
Um jetzt eine Farbe zu wählen, sind wir wieder bei vier Farben.
Wir wählen mit Empf einfach Red, Yellow Blue oder Grin,
Angst davon, gibt Shows, Color zurück.
Wir führen eine Struktur ein, in die wir Länder beschreiben.
Der Name des Landes, die Farbe des Landes und die Farben der Nachbarländer.
Und wenn wir jetzt Europa entfernen, dann könnten wir das so machen.
Also für Portugal rufen wir einfach Juice Color auf.
Tschüss, Kanada, haben wir hier gesehen.
Das macht einen Aufruf von Amt. Ja, das ist
halt diese vier Möglichkeiten. Also eins von den vier Farben
kommt. Für ist bei mir eine der vier,
für France, eine der vier und so weiter.
Und damit haben wir, also jetzt jedem Land gesagt,
du könntest potenziell diese Farben haben.
Die Länder, Repräsentieren wir sie? Also sie machen das Land Portugal,
ist dieses, ist ein Aufruf von Country mit dem Land
Portugal und die liste der Nachbarländer ist nur Espania.
Ja, Spanien hat als Nachbar der Länder Frankreich und Portugal
und so weiter. Frankreich hat ganz schön viele Nachbarländer.
Okay. Also dann machen wir eine Liste der Länder.
Ford You Gold Spin und so weiter. Und jetzt,
wir sind schon mal imperativ,
da können wir es auch voll auskosten und jetzt brauchen wir
auch noch eine
Imperative Kontrollschleife for it. Also für jedes der Länder
in der Liste Countries machen wir einen Amp-Assert.
Und was müssen wir sicherstellen, dass die Farbe des Landes C,
Mamp You, nicht in der Farbe der Nachbarländer vorkommt.
Ja, wir haben die Farbe der Nachbarländer,
die holen wir hier und wir vergleichen die Farbe des Landes.
Also Amp-Assert soll für jedes Land das sicherstellen und das gilt
über die Liste aller Länder.
Und wenn ein Ziel rauskommt, aus dieser Vor-Itch-Leife,
wo jetzt Amp-Assert sich bemüht,
zu gucken
Muss ich dieses verwerfen oder nicht? Muss ich es verwerfen
oder nicht? Dann geben wir anschließend for itch aus,
was ist denn jetzt die Liste der Länder mit ihren Farben?
Und wir sind fertig. Und was kommt zurück? Kalajurup sagt uns dann,
das geht auf, wenn wir Portugal Rot haben,
Spanien, Geld, Frankreich, Rot, Welt,
Belgien, Gelb und so weiter.
Und wenn ich jetzt M sage und frage,
gibt es eine zweite Art, die Lampkarte zu färben,
dann kriegen wir die nächste Lösung.
Also wir haben hier nirgendwo gesucht.
Wir haben einfach nur gesagt,
wie wir es gern hätten
Wir haben erstens dem Programm gesagt, hier von der Menge der möglichen Farben,
such eine Ausfirmen und M bietet an jeder Stelle vier mögliche Farben an.
Dann haben wir als nächstes, hier ein Amp ist Swat
gesagt und dann alles gut, du kannst die Farbe nehmen,
aber sie muss unterschiedlich sein von der Farbe der Nachbarländer.
Das macht Amp Assert und alle Farbemöglichkeiten, die dem widersprechen,
die werden zurückgenommen und man geht zurück zu einem der vielen M-M-Möglichkeiten,
um eine andere Farbe zu wählen.
Und ganz, wenn es da heil rauskommt, können wir
tatsächlich hinterher die Liste der Länderanzeigen und haben deren Farben.
Und das jetzt nur als ein weiteres Beispiel, wir können
unser allgemeines Backbreaking-Verfahren genauso machen mit Amp. Wir fragen bei Iss-Final,
ob das den Zustand, wenn der Zustand legal war,
ja, wir kommen da hin, ist Final,
dann zeigen das an, die Funktion schrei,
die muss nur ein Assort aufrufen machen,
ist Legal.
Die Funktion ist Legal,
die wir vorher übergeben haben,
ist der Zustand legal
Denn fertig ist es Prima. Feine, wenn es eine
Lösung ist und in allen anderen Fällen müssen wir probieren.
Und das eigentlich nur unsere Funktion General States, die wir übergeben haben,
die für jeden Zustand die Menge der Nachfolgezustände gibt.
Und da wenden wir M drauf an. Hier steht jetzt MK,
das ist eine Funktion, die ich in die SE3-Bit reingeschrieben habe.
Wir haben ja gesehen, MP braucht die Argumente flach.
Also was man hier machen muss,
ist eine Ply von Amp auf die Liste,
aber da M Special Form ist,
kann ich es nicht mit Apply draufwenden.
Also muss man eine Funktion schreiben,
die daraus einfach eine Kaskade von M-Aufrufen macht
Das macht dieses MKs, ja. Und ganz am Ende hier das M-Assert,
das prüft, ob das eine Lösung ist, ja.
Okay. Ja, wir haben noch eine halbe Stunde.
Jetzt können wir zu dem Teil kommen, der mir eigentlich
hier so im funktionalen Programmieren am meisten Spaß macht.
Nämlich zu dem Teil, wo wir uns jetzt mal
größere Systeme überlegen, die jetzt funktionale komplett auskosten.
Und die Beispiele, die ich rausgesucht habe, okay,
ich bin von Haus aus im Bereich günstige Intelligenz zu Hause.
Und ich wollte das als Gelegenheit nehmen, um ihnen zu zeigen,
dass die künstliche Intelligenz nicht ein Bereich ist,
wo man einfach abgehoben nutzlose Dinge macht, sondern dass da solide Softwaretechnik gemacht wird.
Und schöne Entwurfsmuster erfunden wurden, an denen man Komplexität von sehr schwierigen Problemen untersuchen kann,
eben solchen, wo sehr viel probiert und gesucht und Lösungen gefunden werden müssen.
Und dass es dann schöne Werkzeugkisten gibt, die genau das machen. Deshalb,
die folgenden drei Beispiele, die ich zeige,
haben alle aus dem Buch von Peter Norwick, AI-Programming,
der als erster wirklich ein Buch geschrieben hat,
wo er gezeigt hat, dass die künstliche Intelligenz wunderbare Entwurfsmuster hat,
mit denen man tolle Probleme lösen kann.
Und wir werden an diesen Beispielen sehen,
wie wir die Kontrollabläufe, die wir jetzt gefunden haben,
zu Werkzeugen verallgemeinern, die wir denn für andere Sachen einsetzen.
Also im Beispiel des Eliza-Programms,
das von Weizenbaum populär gemacht worden ist, können wir sehen,
was von der Architektur her ein regelbasierter Übersetzer ist,
bei dem wir Pattern-Matching üben können und an dem wir Daten orientiertes Programmieren im Datengesteuertes Programmieren üben können.
Das heißt, im Leiser-Programm werden wir sehen,
die Abläufe können wir extrahieren und als Bausteine zur Verfügung stellen
und was man dann einfach nur tut muss,
um das zu verwenden, ist, dass man andere Datenbasen macht.
Genauso wie sie es im Pro-Lock machen,
wenn sie ein Pro-Lock-Vorlesung hier das relationale Programmieren üben.
Also Elisa ist der erste Weg, um einen Schritt,
um in diese Richtung zu gehen. Wir werden sehen,
wie wir Werkzeuge isolieren, die wir für andere Sachen verwenden können.
Das andere Beispiel, was ich noch vorstellen möchte,
ist das Programms Juden, das ist Ein Ur-Ur-Ur-Arne von Programmen wie Mathematiker.
Was wir in Student üben, ist, dass man Textaufgaben stellt.
Wenn Eier dreimal so viel kosten wie Kuhlköpfe und
sie wollen drei Kohlköpfe kaufen, was kosten zehn Eier?
Textaufgabe als Text geschrieben. Also Aufgabe von Student ist es,
die Textaufgabe zu lesen, die Gleichung zu extrahieren und dann
die Gleichung auch zu lösen.
Und das machen wir mit den Werkzeugen,
die wir hier bauen
Eliza, als es zuerst veröffentlicht wurde vom Weizen war,
ein Programm, was viele Leute verblüfft hat.
Und Weizen warum halt viele Jahre später nochmal in seinem schönen Buch
die Macht der Computer und die Ohnmacht der Vernunft ein paar Sätze dazu gesagt,
was eigentlich zu diesem Überraschungseffekt geführt hat.
It's said, that to explain is to explain a way,
this maxime is no, were so werelful
filters and the area of computer programming, especially,
what is quite uristic programming in artificial intelligence.
For in those flares machines are made to be have in wunders ways
offen zu fischen, tut Deserviven the most experienced of server.
But wants a particular program is an mask?
Wann sitzt in der Workings explained, in the Language,
the ficialtly plain to induce understanding?
It's magic a crumble the way. It's stands reviewed as
a mear collection of proceders, it's quite comprehensible.
The observer as systems of, I could to britant that.
The that tor the moves the program in question from the
shelf market intelligent to dettory surf for a curious,
for it to be discussed only the people less end
lightened in lightened any. The object of this paper is
to course, just such a real valuation of the program
about to
be explained
Few programs, every needed at more. Also von Weizenbaum.
Ich habe es in der Form zitiert, wie es bei Peter Norwegg steht.
Ja, also was es sagt, ist,
wenn wir ein Programm haben, das so Eindrucksfall ist.
Es kann überraschende Dinge und wir sagen, wow.
In dem Moment, wo jemand erklärt, wie das alles funktioniert,
dann sagt man, boah, das hätte ich auch machen können.
Und das ist eigentlich immer so bei Programmen,
die viel suchen, kombinieren und so weiter.
Weil wenn man erstmal verstanden hat, dass man
das vernünftig programmieren kann
Wenn man die richtigen Werkzeuge hat, dann ist es eben auch relativ simpel.
Dieses Eliza-Programm, ich hoffe, Sie erinnern sich daran,
wenn Sie es schon gesehen haben, das war ein Versuch,
Gesprächstherapie zu simulieren, aber ein recht einfacher Weise.
Ja, wir haben, also unsere Eliza-Dahlsitzung bietet psychiatrische Hilfe an.
Patient kommt. Und bei der Gesprächspirapie kommt es ja darauf an,
dass Psychiater, der Psychiaterinnen und Patienten dazu bringen sollen,
indem man einfach sorglos daherredet,
mit einmal Dinge zu sagen,
die einem
eigentlich nie sagen wollte
Und dann werden dinken Probleme offensichtlich, wenn man nur lange
genug mit ihren Smalltalk macht. Und genau das hat Eliza gemacht.
Also erstens gut zugehört und zweitens versucht, Stellen zu finden,
um meinen Patienten oder Patientin dazu bringen muss, aus sich herauszugehen.
Und die Dinge, die für diesen, diese Gesprächstherapie gebraucht wurden,
also um einfach so einen Dialog mal nachzumachen,
die sind gut geeignet, um einige KI-Werkzeuge kennenzulernen.
Also das Wichtigste, der wichtigste Baustein in Eliza überhaupt,
ist ein Patternmatcher
Das ist Pattern Matching, heißt Muster, die man hat,
abgleichen mit anderen. Also in dem Fall das, was Patient,
Patientin gesagt hat, mit einer Liste von kritischen Fragen,
sodass man dann der Doktor nachfragen kann, aha,
du hast gerade deine Mama erwähnt, erzähl mir mehr über deine Familie.
Also Pattern Matching vergleicht das, was die Patienten sagen,
mit Fragen und gibt dann, erzeugt ihn automatisch die Rückfragen.
Und dieses Pattern Metzing als Baustein ist wunderschöne Rekursive Algorithmus,
den es sich lohnt, sich mal anzugucken und dann als Werkzeug bereitzuhalten,
sodass man es nie wieder selbst programmieren muss.
Genauso wird es beim Wegtracking gemacht haben. Außerdem,
wie bauen wir funktional ein größeres System auf,
in dem wir modular viele, viele Funktionen,
höhere Ordnung als Kontrollablauf haben und sie mit anderen Funktionen parametrisieren.
Okay. Also der Originaldialog von Ileisa,
wir von Weizimmer ursprünglich veröffentlicht wurde,
also in dieser kleineren Buchstaben
hier,
das ist da
Patient Patientin, in dem Fall eine Patientin, Männer all
a like. Wie leider fragt zurück in What way.
The all way's bugging as about something way in other.
Can you be more specific, well, my boyfriend meet
me come here? You're boyfriend meet you came here,
he saids I'm deepressed much of the time.
I'm sorry to hear you are depressed.
It's too, I'm unhappy. Do you saying,
coming able help you not to be unhappy?
I need some how that much a serten.
For it means to you have
you got somehow
I could lawn to get on long this my mother.
Town me more about your family. Da ist es zum
ersten Mal etwas Interessantes aufgetaucht, nämlich sie hat Patientin,
hat die Familie erlehnt und dann wird eine Gesprächspyrapie,
die fährt voll drauf ab und fragt jetzt nach der Familie.
Das ist ja morgens, du bist ja draußen in die Freude,
du bist ja tot, weil Gott meine Mutter verbaut hat sie bekommen,
hier zu sein, also investor, so befreien,
alles, was die Bühne war.
Vers nur, wie viel willkommen hier,
kommt die Baute
Wenn man hat es so erfüllt, sind die Leute aufgeregt,
sind aber aufgeregt. Also als Eliza rauskam,
war es so populär, dass diejenigen,
die den Imax-Editeur geschrieben haben, also einer der ersten guten Editoren,
die mit Unix-Systemen auf den Markt kamen und sehr beliebt waren,
da wurde gleich Eliza eingebaut,
dass die Benutzer von dem Imax immer gleich psychiatrische Hilfe kriegen konnten.
Man ist einfach nur mit der Exdoktor eingeben und
sofort hatte man Therapie und hat es dann den Editor
ein bisschen länger überstanden
Ja, also was an diesem Dialog so wichtig,
also ab der Oberfläche, da wirkt es doch so,
als ob diese Eliza tatsächlich versteht, was die Patienten sagen.
Antwortet wie ein normaler Mensch, I'm sorry to your,
your are depress, time me more about your family.
Aber wenn man da reinguckt, dann stellt man fest,
dass Eliza wirklich nur schematisch auf die Muster in der Angabe reagiert,
die auf einzelne Worte,
Eingabemuster werden auf zufällig auf passende Ausgabemuster abgebildet und wenn zum Beispiel,
wenn in der Eingabe von Ähnlichkeit gesprochen wird,
da kommt Like oder Sam
Dann wird eine Frage generiert, in der zurückgefragt wird,
in Whatway, ja? Oder wenn wir ein Lied,
Herrepatte, Patientin gesagt, wenn das vorkommt, dann wird zurückgefragt,
was wurde meant to you if you got, ja?
Das Problem ist, Elisa Dialoge bringen Spaß,
solange wir tatsächlich aus uns rausgehen und der was verraten.
In dem Moment, wo wir mauern und gar nichts sagen,
dem wird ziemlich leicht langweilig. Und dann kriegen wir einfach
nur so Gorn, please continue, very interesting.
Hier ist die Rechnung. Und die Muster,
die erfassen die Semantik auch nicht wirklich, ne?
Also wenn man Leiser sagt,
I need this like a hol in the head,
dann könnte zum Beispiel rauskommen,
what would it mean to you if you got it like a hole in the head, ja?
Oder I vonne to rubber, suppose, you got to borrow the suhn.
Also Leiser fängt dann an mit einer ganz anderen Sprache zu sprechen, grammatikalisch falsch.
Zum Zeitpunkt, als Leiser rauskam und eine Furore gemacht hat,
da gab es psychologisch viel Wichtigeres Experiment,
da wurde auch ein künstlicher paranoide programmiert, der hieß Perry.
Und ganz berühmter Dialog ist zwischen Eliza und Perry,
der hat mir beide aufeinander zugelassen
Weil mit jemandem, der schüttelt, die Weide,
das ist ja der Bundestag, das ist ja die Früchte.
Also die Früchte, das ist ja die Früchte.
Also man sieht hier zum Beispiel, you help on the same question,
das Schlüsselwort im Muster, was Eliza versteht,
ist Szenen und sofort fragt sie nach der Similarity.
Und ansonsten immer mauern und warten, da kommt irgendwas und dann machen wir weiter.
Dann gucken wir uns mal auf jeden Fall so einen
Die hatten eine Gesprächstherapie programmieren könnte. Also die Teilaufgaben,
die Eliza lösen muss, ist, lese die Eingabe.
Ein passendes Muster suchen, ja, aus der Eingabe eine Ausgabe machen.
Und dann die Oscar beschreiben. Also ein Racket und Scream eingebaut,
da haben wir die fertigen Funktionen, Read and Ride.
Und damit können wir die Eingabe lesen und damit können wir auch die Ausgabe schreiben.
Der Musterabgleich, das ist jetzt wirklich der Kern.
Wenn wir, wenn die leider feststellen will, sagt jemand Need,
ich brauche was. Dann möchte man Antwort geben,
what would it mean to you if your god?
Also die Muster enthalten, feste Textstücke und dann Variable.
Die Variable wird an die Eingabe gebunden, genauso wie man
in Pullock mit Unifikationen aus der Eingabe Variablenbindung erstellt.
Und dann erzeugen wir eine Oscarbe, wo der Wert der Variable,
die wir rausgezogen haben, aus dem Muster denn eingesetzt wird.
Also wenn zum Beispiel die Eingabe ist, ein Need Ovocation,
dann würde mit dem Muster ein Need X und what
would you mean to your cheo god,
der Ex,
würde rauskommen,
what would mean to you have to got
a Vacation
So, und im Kern ist der Pattern-Matcher eigentlich ein wunderschönes Beispiel für eine Baumrekursion.
Und die können wir uns so vorstellen. Also wir haben hier
das Muster, ein Lied der X zum Beispiel, ja.
Und die Angabe. Und dann im Pattern-Matching fragen wir einfach,
wenn die Eingabe überhaupt nur eine einfache Variable ist,
dann kommt Truh zurück, ja.
Die einfache Variable passt immer, die kann
ans ganze Muster gebunden werden
Wenn es aber ein Paar ist, dann gucken wir,
ob das, wenn es kein Paar ist,
dann gucken wir, ob das Muster gleich der Eingabe ist.
Und wenn es aber ein Paar ist, dann müssen wir
den Kopf des Musters vergleichen und den Rest des Musters vergleichen.
Wir rufen also Reco, sieht Peter ein Matching auf fürs
erste Element und für den Rest. So,
jetzt müssen wir uns eine Datenstruktur überlegen, wie wir Variable kenntlich machen.
Und ich bin da der Vorgabe von Peter Norwick,
gefolgte das Assemble-Programm von Weizenbaum überführt hat in ein ein kommendes Programm,
diskommendes Programm habe ich für Sie in Racket übersetzt.
Also der Vorschlag von Peter Norweg für Variabliver,
dass man einfach als Variable ein Symbol nimmt, dessen Name mit einem Fragezeichen beginnt.
Und das machen wir, indem wir testen, ist X ein Symbol.
Und dann fragen wir, ob das erste Zeichen,
wenn wir simple to string machen, also den bringenden Symbolnamen uns angucken,
ob das gleich im Fragezeichen ist.
So, dann machen wir beim Pattern Matching,
zum Beispiel unsere Funktion von eben, ein Needle X,
In der Nieder Vacation kriegen wir zurück, ja, es ist True.
Oder ein Niederex. Und die Angabe ist ein Niedmani,
kriegen wir Folks zurück, weil da das A fehlt.
Okay. Und ein Niedx mit Arealy Need, das matcht eben nicht.
Hier sehen wir unser X mit dem Fragezeichen davor.
So, es ist jetzt ein bisschen wenig hilfreich,
wie das Pattern-Matching implementiert ist, weil es uns die Variablenbindung nicht zurückgibt.
Das ist so ein bisschen wie, wenn wir fragen,
weißt du, wie es Betes ist und ich kriege die Antwort,
ja, nicht die Uhrzeit.
Also wir wollen tatsächlich dann die Variablenbewegung,
Belegung zurückkriegen
Und deshalb erweitern wir das Padmatch so,
dass wir eine Liste der Variablenbindungen kriegen.
Und dann damit weitermachen können. Und wenn wir die Variablenbindungen haben,
können wir die Ausgabe erzeugen mit der Funktion Subliss,
die nämlich dann jede Variable im Muster ersetzt mit dem Variablen,
die wir extrahiert haben.
Gucken wir uns erst mal das Zepness an.
Wenn wir hier die Liste Expecation haben,
what would it mean to you if you got and ex,
dann würden wir in dem Fall X
ersetzen durch Vication
Wir haben hier die beiden Ersetzungsmöglichkeiten, Y,
Soldat Hugh ersetzt werden und X durch The Vecation.
What the would it mean to you? If,
hier kommt das Y vor und ein Y-Gott in X.
Und dann wurde dann das Y durch Y ersetzt werden.
Um jetzt die Variablenbelegung zurückzukriegen, machen wir Padmatch zu einem Simi-Predikat.
Also bisher kriegt man immer nur Truhe in Volks zurück und
wir wollen jetzt aber natürlich die richtigen Werte haben.
Und dazu müssen wir jetzt aber sagen, ob das leere Resultat,
was zurückkommt, ob dessen Fehl bedeuten soll oder ob tatsächlich das Muster gepasst hat.
Und es gab nur keine Variablenbindung, das können wir nicht unterscheiden.
Und deshalb dürfen wir in dem Fall,
wo es keine Variablen gab, nicht einfach Volks zurückgeben,
sondern wir geben die leere Liste von Variablenbindung zurück und sagen damit,
ja, das Matching war erfolgreich, aber es kam gar keine Variablen vor in dem Muster.
Wenn es nicht passt, dann geben wir Volks zurück.
Und dazu führen wir dieses komische No-Beindings hier ein,
einfach ein Bindungswertbar, was einfach aus zwei Trust besteht
Wir brauchen Stützfunktionen, um die Bindung zu kriegen.
Get Binding Binding, weil Look-up und so weiter.
Und um die Liste zu verlängern, Extent Bindings,
die Funktionen müssen wir uns die im Detail angucken.
Das andere, was noch wichtig ist,
diejenigen von ihnen, die im Prolog programmieren, wissen,
dass man sich um Co-Referenz bei den Variablenbindungen kümmern muss.
Das heißt,
wenn man an irgendeiner Stelle im Muster dieselbe Variable mehrfach haben,
dann dürfen wir dieses X hier nicht,
wenn es jetzt das Beispiel ist,
in Ulm,
Ulm und Ulm herum
Dürfen wir das X nicht einmal in Rom binden und
einmal in Ulm, sondern es ist nur erfolgreich,
wenn es an allen Stellen an Ulm gründen wurde.
Das ist die Korreferenz, gleiche Variablen bezeichnen immer denselben Wert.
Und auch das müssen wir noch in den Pattern-Mitte einbauen.
Und das machen wir jetzt in einer etwas anderen Form.
Testfrage an Sie. Wir haben das Rekursionsschema,
hat sich jetzt ganz leicht verändert. Welche Art von Rekursion
haben wir hier? Also vorher hatten wir eine simple Baumrekursion
Hier haben wir als Pattern Matching, es ruft sich selbst immer noch zweimal auf,
aber der zweite Aufruf ist hier auf Parameterposition, ja?
Das ist eine Geschachtelte, genau. Das ist eines der typischen Muster,
wie man geschachtelte Rekursionen verwendet, wenn man Ergebnisse von vorherigen Aufrufen weitergeben will,
macht man das gerne, indem man das, das,
was man für das erste Element macht,
auf Parameterpositionen übergibt und genau das wird hier gemacht.
Der Pattern Matcher,
wenn er die Restliste vom Muster und von der Eingabe vergleichen will,
braucht er die Bindung,
die bei den vorherigen Aufrufen geschehen sind und deshalb wird an der Parameterposition,
wo die erzeugten Bindungen übergeben werden, steht hier jetzt der rekursive Aufruf,
um das erste Element vom Muster mit dem ersten Element der Eingabe zu vergleichen.
Da werden, also das, was hier zurückkommt,
an Bindungen wird genommen, um das Pattern-Matching für die Restlisten zu machen.
Das ist eine ganz typische Anwendung für geschachtelte Rekursion.
Hier ist sie nicht ineffizient, sondern da ist sie einfach genial und simpel.
Ich brauche, wenn ich den Rest vergleiche, muss ich
die Bindungen verwenden, die ich beim Vergleich der ersten beiden Elemente hatte.
Und deshalb, Rufe, mache ich da den rekursiven Aufruf
für den Vergleich der ersten Elemente
Und ansonsten ist es ja übersichtlich, wenn die Bindung,
wenn ich überhaupt keine Bindung habe,
dass es schon fehl ist, dann höre ich auf.
Wenn es eine Variable ist, dann mache ich nur ein
Match Variable und da vergleiche ich das Muster und die Variable,
wenn es dann Variable sind.
Und der Beobachtung der Bindung, die ich schon habe,
wenn es ein Paar ist, zerlege ich es in erstes Element und Restelement.
Und dann haben wir das. Die Variablen zu vergleichen,
das lassen wir mal. Gucken wir uns mal das Extentbein,
den brauchen wir auch nicht. Einfach ein paar Beispiele.
Was unser Pattern-Matcher jetzt kann, also wenn ich hier X
und um X herum mit innen Ulm, um Ulm und irgendwo hin herum.
Zum Matchen bringen, dann kriege ich eben als einziges Resultat draus,
dass Muster passt und X-Mus wird an Ulm gebunden, dann sind sie gleich.
Wenn ich hier dann rum zwischen schmucke, dann geht es schief,
weil wir eben die Choreferenz nicht haben.
Es geht auch für zusammengesetzte Ausdrücke,
also wenn ich X plus X mit 1 plus 1
binde und ich habe noch keine Bindung, ja,
dann kriege ich raus.
X ist 1, ja, oder X mal X hier reinnehme,
dann kriege ich in dem Muster nur eine einzige Bindung,
nämlich hier für 3 mal
Das hat auch geklappt. Was jetzt noch fehlt,
das Subliss, um die Ergebnisse reinzukriegen, also wenn wir jetzt
die Ergebnisse zurückkommen, kann ich eben die X-Strifffication ersetzen.
Denn die nächste Komplikation, da welches Programm nicht voll erklären,
aber wer Lust hat, kann das bei Peter Norweg nachlesen.
Das ist eigentlich gar nicht so schwierig. Um das
wirklich voll lizer-mäßig zu kriegen, brauchen wir Segmentmuster.
Also wenn ich zum Beispiel nur das Wort Neat finden will,
in einer langen Liste von Worten,
dann habe ich hier so ein Segment von Worten,
die da vorkommen können und ein Segment von Worten,
die danach kommen
Und solche Segmente sind hier durch Fragezeichen, Sternen und P
markiert. Das Segmentmatching ist dann wichtig, dass man so
ein einzelnes Wort aus dem langen Text rauskriegen kann.
Und wenn wir auch das noch haben,
dann haben wir das volle Pattern-Matching erledigt und sind fertig.
Ein Problem weshalb Segmentmatching so schwer ist, das möchte ich hier noch kurz zeigen.
Also wenn wir hier sowas wie ein Iss-E drin haben,
ja, und das, die Eingabe,
mit der wir das vergleichen wollen,
das ist hier zweimal,
what he is is a fool
Dann muss man entweder mit dem Ersten es anfangen oder mit dem Zweiten.
Du musst beides systematisch durchprobieren. Und das ist erstaunlich schwer zu programmieren.
Also die meisten Pattern Metzger schummeln an der Stelle und es
klappt nicht immer. Auch der, den wir nicht leiser haben,
macht das Segment Metzing so, dass es nicht immer klappt.
Muss man mitleben. Gut. Ansonsten gucken wir uns jetzt
mal an, wie Eliza wirklich funktioniert.
Die Datenbank im Leiser, die besteht aus Eingabemuster.
Also einfach eine Folge von Regeln, ja.
Und dann kommt für jedes Eingabemuster eine Zahl von möglichen Antworten.
Alles ist mit Variablen parametrisiert und die Leiser würfelt jedes Mal.
Also wenn es das Muster hier erkannt hat,
dann nimmt es aus den vielen Möglichkeiten eine.
Und die Regeln sind oft gebaut, indem wir ein Melkrol haben,
was einfach nur Muster und Response zusammenbringt.
So, und wir haben extra Opzessefunktionen,
um das Muster und die Antwort zu kriegen.
Also ein Beispiel, was sind die Leiser stehen könnte,
so ein Segment hier, ein bisschen Sex,
dann kommt albern und dann kommt wieder ein bisschen Text.
Und dann können wir als Antwort generieren,
what would it mean if you got?
Und dann wird dieses Y hier eingesetzt,
Weil du Yvonne oder Suppose You God. Also immer wird hier erkannt,
ich möchte was und es gibt einen Y und das wird dann da eingesetzt.
So die ganzen Regeln, die ihr leiser habt, sind in einer Suchliste.
Und die werden so geordnet, dass die spezifischesten am Anfang stehen.
Und die langweiligen Verlegenheitsantworten kommen weiter unten. Also in der Eliza-Datenbank hätten wir zum Beispiel einfach,
irgendwo taucht das Wort Hello auf, dann fragt die Leide zurück,
hau du, you do, please that your problem.
Wenn wir jetzt Yvonne sagen, dann kommen eben diese verschiedenen Varianten von iWant oder wenn wir Zweifel ausdrücken,
ein If, kommt zurück mit Guerilla,
die think it's likely, do you wisst that,
what do you think gebaut, really if, ja,
eine dieser Möglichkeiten wird genommen und das wird einfach eingesetzt.
Auweia, man sagt zu Eliza No,
dann wird sie böse, dann kommt buy not,
oder, you are, buying it, negative,
I you seeing, no, just to be negative,
also of no,
wird unfreundlich reagiert und man soll wieder was Positives sagen.
Und wenn man sagt, I wusste, dann wird Zweifel
ausgerückt, stimmt das überhaupt? Ja, Jureali,
Papstai ora di new you were, by do you tell you were.
Und wenn wir über Gefühle reden, you offen feel,
I felt that are feelings do you have here?
So, also mit dieser Liste von Regeln,
in dem Pattern-Matcher gesucht wird, sind wir schon fast fertig.
Was wir jetzt noch brauchen, ist die Dialogschleife.
Ein Promptzeichen wird gedruckt, dann wird die Angabe-Metrie gelesen.
Es wird eine fassende Regel gesucht, eine Antwort generiert,
die mit Freitlein ausgegeben, so lange bis Patient, Patientin einen Ball machen.
Der E-Max-Editor hat am Ende ja immer noch eine Rechnung geschickt,
fand ich recht unfreundlich. Okay, also dieser News-Elizer-Rult,
das macht jetzt die Transformation der Eingabe, verwendet einen Sam.
Das ist ein Funktion höherer Ordnung,
die einfach aus einer Menge von Argumenten dasjenige raussucht,
eins davon raussucht, was die Bedingung erfüllt, wie als nächstes kommt.
Also die Ruhe muss dies hier zu einem Tor bringen.
Und das wird auf sämtliche Regeln angewendet. Dann kriegen wir
diese Regel zurück. Wichtig ist noch, dass Switch View-Freund,
wenn Patient, Patientin, Ei oder so sage,
dann musste Eliza mit Youth zurückfragen.
Also die ganzen persönlichen Worte müssen ins Gegenteil verkehrt werden.
Und das Eliza-Programm selbst ist jetzt einfach eine Kaskade von Funktionen
höherer Ordnung,
die diesen Ablauf machen
Die fallen Eliza. Als erster mit der Dialogfunktion,
die ruft hier die Stews Eliza Hools auf und schreibt denn das Ergebnis,
liest mit Input,
Metried wendet darauf die Regeln an und schreibt dann das Ergebnis raus.
Und das Ganze macht sie Itterates an Till, die Funktionen,
die wir vorletztes Mal eingeführt hatten, wird Dialog aufgerufen,
immer wieder auf die Eingabe der Dialog angewendet und wir hören auf,
wenn es als Resultat bei zurückgekommen ist.
Claudia Xvoll beide, dann sind wir fertig.
Und dann sagt Eliza, ciao
Der Switch YouPoint verwendet Zubles, um ein I don't you
zu ersetzen. Judurch, I, me do you,
M durch A, also in der Liste aller Worte.
Und jetzt können wir mit Eliza loslegen. Wir rufen es
mal auf. Können Sie aus der SE3-Bib sich ausrufen?
Nun sagen, hello da, dann kommt Ihr Eliza,
sagt, how do you do, please date your problem?
Es hat das hello erkannt, ja. I want to test
this program. Da steht want. Auf want wird reagiert
mit. Zum Beispiel You You want, du test disprogram.
I could see if it works. Jetzt kommt, das
ist hier. Oh, da kommen denn diese Zweifel,
ja?
Really if it works
Nun, Notrealie. Ja, jetzt reagiert sie,
ob das nur, you are being a bit negative.
Ich sag nur, are you seeing no just to be negative?
You say, forgotted, I was wondering how general
the program is. Where you really? By do you
time me you were undering our general the programism out?
I felt like it. But other feelings to you have.
I feel this is enough. Do you offen feel,
this is see noth? I do. I'm not sure in a
stand you folity. Da ist jetzt überhaupt nichts drin,
worauf Glaser reagieren konnte. Kommt eine der Verlegenheitsantworten. Was
wir als nächstes machen werden, aber nicht mehr heute,
das ist, dass wir jetzt das,
was wir an Bausteinen in den Leiser geschaffen haben,
zu Werkzeugen abstrahieren und dann damit das nächste große Projekt angehen.
Danke für die Aufmerksamkeit