Das letzte Mal damit aufgehört, dass wir nochmal uns an
die Semantik von Reckett zurückerinnert haben und die verschiedenen... Dialekte kontrastiert.
Das heißt, wir haben eigentlich nur zwei von den Dialekten besprochen,
aber vor allem eben das Standard Reckett,
wo sie in den Modulen langen Reckett schreiben.
Und dann haben wir als zweites noch besprochen,
die Variante von Lesi ist eine eigene Programmiersprache. Ja,
es sieht aus wie Reckett, aber wenn man vergisst,
langen Lesi zu schreiben, dann passiert abenteuerliches und die Sachen funktionieren nicht.
Also wenn man zum Beispiel hier auf diese Funktion hier schauen,
weshalb kann die überhaupt nur funktionieren, indem wir in der Sprache lese sind?
Also ich sage das jetzt ein bisschen so als Leseübung für Programme,
während der Klausur bitte sehr genau drauf,
was in der langen Language-Zeile steht,
ob da Lesi oder Recket steht.
Ja, es kann sein, dass sie gefragt werden,
welche Sprache schreiben wir da am besten hin von den beiden.
Weshalb muss es in diesem Fall hier
die Sprache Lesi sein
Gut, frage ich mal ein bisschen andersrum.
Wir sehen eine Funktion und wie hier farblich hervorgehoben habe,
das wird in der Klausur nicht sein.
Wir können es uns nicht leisten, alle Klausurbogen farbig drücken
zu lassen. Aber hier können wir gut sehen,
das Wort Chief kommt zweimal vor.
Liegt nahe, dass es eine rekursive Funktion ist.
Jetzt fragen wir doch erstmal,
welche Art von Rekursion
das ist
Ja? Das ist eine Flussreklusion. Gut. Endlosrekursion,
kann man schon mal sagen, aber da kommen wir
zur Frage von wegen, lang lese ich zurück.
Und wenn wir auf das Rekursionsschema schauen, ist diese Rekursionsschema Lindejahr baumartig.
Es ist endrekursiv. Hier? Es ist intrekursiv, ne?
Woran erkennen wir es? Weil die Funktionen hier aufgerufen wird und wenn sie zurückkommt,
müssen die Ergebnisse nicht mehr mit anderen verknüpft werden.
Deshalb ist es eine entrekursive Funktion. Also die falscheste Antwort,
die man in der Klausur geben kann, kann bei der Frage,
warum ist eine Funktion endrekursiv zu sagen, weil eine Kumulator da ist.
Akkumulator ist ein guter Hinweis, dass das endrekursiv sein könnte,
aber die Existenz eines Akkumulators als Technik für die Rekursion ist wederhin reichend noch notwendig.
Es gibt genug Funktionen, die ein Akkumulator haben,
damit man wenigstens von der Baumrekursion wegkommt, aber die trotzdem nicht endrekursiv sind.
Und es gibt genügend Funktionen, die endrekursiv sind,
ohne dass hier irgendwo ein Akkumulator steht.
Ja, wenn er nicht gebraucht wird, braucht man ihn nicht so.
Und in dem, also hier haben wir eine Endrekursion,
Sifkehr zurück ist Liefert das Ergebnis, muss mit nichts verknüpft werden.
Wir haben das Versprechen aus Recket, dass dann kein Aufrufsdeck gemacht wird,
wo man zwischen Argumente übergibt und so weiter,
sondern es wird beim Compiler übersetzt in eine reine Iteration.
Jetzt hatten Sie ganz richtig gesagt, ja, aber das ist
eine endlose Rekursion. Warum? Bemerkung dazu? Ich dachte,
ich weiß nicht, ob ich jetzt die gerade falsch erzähle,
aber ich habe das wirklich gewusst,
dass es einfach auf dem Platz läuft, Das kann gut sein,
dass wir beim Umsetzen eine Klammer abhanden gekommen ist.
Gucken wir mal, die macht Kötter zu, die macht tief zu.
Die macht, sollte den Aufruf von Filter zumachen.
Das Kötter sollte hier zugehen und das ist die Feind da.
Gucken wir mal, ob das Filter hier genug Klammern hat.
Cast, Stream, not devisible. Da schließt der Lamda
ab. Also eigentlich müssten sie aufgehen. Also wie es
eingerückt ist, sollte es sein. Tun wir mal so,
als wären wir hier in einem Meter Klammer,
die alles zumacht
Also, wir haben hier die Klammer für Kötterstrehen,
hier fürs Zief, die macht das Fild dazu,
die macht das Kunst zu und die macht das die Feind zu.
Also, es ging nie darum, dass der Zief ausdrückt,
ja, noch mit dem Paar gepanzt wird,
das heißt, du fährst doch da.
Ah. Ja. Genau. Stimmt. Ich hatte mich da
eben selbst täuschen lassen, das konstituiert hier ziemlich weit entfernt.
Ja? Es ist richtig, ist eine allgemeine lineare Rekursion
gut erkannt
Okay, also ganz weit nach oben gucken, ob da oben noch was steht.
Okay, ja. Also das ist tatsächlich eine allgemeine lineare Rekursion.
Trotzdem, ich wollte auf die Antwort von vorher zurückkommen,
die gesagt hat, die ist unendlich, die terminiert nicht.
Deshalb geht das gut. Hm? Ja? Fabian,
das ist ja noch besser, die laufen nachzuausweisen.
Schrift. Also wir können uns in der Sprache Lesi
Das haben sie gut gesagt. In der König der Sprache,
Lesi, bei Rekursionen die Abbruchbedingungen sparen,
wenn wir es einfach als potenziell unendlichen Strom aufsetzen wollen und die Auswertung,
die Verzöger der Auswertung sorgt dafür,
dass immer nur so viel gerechnet wird von dem Resultat,
wie uns interessiert.
Ja, wir müssen einfach bescheiden sein, wenn wir Lesi
benutzen und immer nur nach einer endlichen Anzahl von Elementen fragen,
dann brauchen wir keine Abbruchbedingung. Also zum Beispiel,
bis hier unten steht, ja, hier steht das Ausrufezeichen,
Ausrufezeichen, das ist die Kurzform für Fonds und mit diesem Fonds Sorgen wir dafür,
dass der Aufruf von Take hier ausgewertet wird,
über die ganze Länge, Take nimmt die ersten zehn Elemente des Resultates hier.
Und das Bang Bang sagt,
werte das bis zum bitteren Ende aus und das geht gut,
weil wir hier nur die ersten zehn Elemente genommen haben.
Also wenn wir in der Sprache Lesy arbeiten,
dann können wir uns darauf verlassen, dass immer nur ein Schritt gemacht wird,
der uns das nächste Element des Ergebnisses gibt,
eben das, was mit dem Konzil davor gehängt wird,
gab und der Rest, der wird eingehüllt in ein Promis,
ein Versprechen, dass es ausgewertet wird,
wenn es gebraucht wird.
Wenn man nach dem nächsten Wert fragt. Und normalerweise werden wir,
wenn wir mit Lang Lesi eine Endpotenziell endlose Liste auswerten,
wird uns immer das erste Element gegeben.
Das kriegen wir. Und dann sehen wir einen Punkt und
dann kommt Promise und das ist das Versprechen,
der Rest wird ausgewertet, wenn wir es denn wissen wollen.
Und dieses, den Rest nehmen, dazu reicht es noch nicht zu sagen,
Tick 10, nimm die ersten 10 Werte.
Davon kriegen wir trotzdem nur das Erste. Aber dieses Bang Bang davor,
das sorgt dafür, nun mach mal jetzt Du fauler Sack,
ja, lesy, komm in die Hufe und rechne das bis zum Ende durch.
Und das Bang Bang dürfen wir wirklich nur verwenden. Wir wissen,
dass das Resultat endlos ist,
sonst wird das hier tatsächlich bis ans Ende aller Tage oder solange der Prozessor durchhält,
versuchen, die Liste der natürlichen Zahlen zu berechnen, ja.
Okay, gut. Das war also das eine Beispiel,
wie wir mit Lesy Racket potenziell unendliche Sachen berechnen können.
Ich komme hier nochmal auf ein anderes Beispiel zurück.
Wir hatten Zu Anfang des Semesters uns als erstes Beispiel fürs Arbeiten mit Symbolen
eine Grammatik definiert. Und für diese Grammatik einen Sprachgenerator geschrieben,
wir haben ein kleines Programm,
das nahmen sich die Grammatik und hat uns dann beliebige Sätze dieser Sprache erzeugt,
sodass wir einfach beigegebener Grammatik irgendwas sagen konnten.
Der Tisch auf dem grünen Stein und was weiß ich,
das war ein ziemlich absurdes Thema,
aber es hat einfach englische Sätze gebaut aus zufälligen Worten und immer Incentence und dann nown frace und so weiter.
Ja. Und ein kleines Problem war dabei,
weil die Grammatik potenziell unendlich war, konnte es uns passieren,
dass wir wirklich endlose Sätze bekommen, die gar nicht mehr aufhören.
In dem Moment, wo wir eingeführt hätten,
dass man beliebig viele Adverbien oder Adjektive einfügen kann.
Der große grüne blaue Ball neben der roten jungen Frau und so weiter.
Und damit hatten wir etwas, was eigentlich in der Sprache Rackett gefährlich ist,
weil wir dann dafür sorgen müssten,
dass das Generate irgendwann wirklich aufhört
In der Sprache, Lesi, ist es kein Problem.
Da können wir das Generate All genauso schreiben. Ich glaube,
ich gehe noch mal zurück auf die Stelle,
wo wir uns an die Grammatik erinnern können.
Mensch. Listen mit Symbolen
Ja, das war die Stelle. Na,
wir hatten Folgendes gemacht, dass wir eine Sprache definiert hatten,
die hattet ihr mit Gaminalsymbole, die konnte Sätze erzeugen.
Wir hatten Regeln, ja. Und dann durch Konkurrenationen
von solchen Phrasen kriegten wir am Ende Sätze der Sprache.
Und geschrieben haben wir das dann so,
die Finance Sentence und dann kommen eine Non-Freeze und Awapfreeze,
die Aufrufe Non-Freeze, das entsprach genau einem Mitter-Symbol der Sprache.
Und dann Naunfrieds hat geguckt, ja, wie sieht denn
so eine Nominalphrase aus? Ach so, ich muss einen
Artikel nehmen und einen Noben nehmen. Und bei der Wordpress,
da musste ich einen Verb nehmen und eine Nounfries und dann
musste ich einen Artikel noch haben, wann auf und wann auf.
Und das waren die zufälligen Sachen. Und wir kriegten dann,
wenn wir es aufgerufen hatten, Zentins zum Beispiel,
The Woman hit the Ball oder The Ball like The Woman und so weiter.
Und dann hatten wir das Ganze erweitert,
indem wir hier Regeln eingefügt hatten, das ist das,
worauf wir jetzt hinaus will, adjektiv Stern,
man bliebig viele Adjektive davor setzen konnte oder beliebig viele Präpositionen.
Und damit wird die Sprache,
wurden die Sätze
ziemlich lang
Alles, was, wie ihr euch hingeht,
ihr heißt immer alle in der Realität zu machen, was auch immer.
Ja, ich habe es damals nicht so gesagt,
aber diese Grammatik, dadurch, dass zufällig immer wieder entschieden wird,
mache ich weiter oder nicht, die kann uns bis zum Ende des Universums Objektive da reinschieben, ne?
Der Daumen, der Pegelbilder, wie die C,
sagt jemand, da kommt sie, da, da,
da, da, da, da, da,
da,
Mit den Graf bei dir,
das ist so jede Tiere, das sind Baufelder.
Genau. Und genau dieses, diese endlose Ausgabe,
die können wir jetzt versuchen mit der Sprache Lese hinzukriegen,
sodass man immer nur das erste Wort erfährt.
Und dahin hangeln wir uns jetzt mal wieder zurück.
Dasselbe Beispiel hier jetzt mit Lesi.
Wo waren wir?
Stromorientiert, Ströme
Siebtes Irre, Clostines, das hatten wir das letzte Mal gemacht. Und dieses Generate All,
was jetzt für unseren Sprache den Satz erzeugt,
das ist überhaupt kein Problem, wenn wir dafür die Sprache Lesi nehmen,
dann können wir einfach mutig schreiben,
Generate All für das erste Element der Phrase,
Generate All für den Rest der Phrase.
Wir können unsere Phrase in der Grammatik suchen. Und wenn
das nicht leer ist, dann erzeugen wir einen Strom und
mit Generate All und gucken alle schmeißen alle Werte da rein.
Also das Beispiel ist ein voller Form in ihrer SE3-Bip und da können Sie mal ausprobieren,
also diese Sprachausgabe und alles mit Hilfe von Strömen, kein Problem.
Ja, wir brauchen in der Rekursion dann keine Abbruchbedingungen und sind fertig.
Also bei diesem Kapitel, wie können wir ins eigene Programmiersprachen definieren?
Da haben wir jetzt schon ziemlich viele gesehen. Ich habe Ihnen nicht gesagt,
wenn man Zählers implementiert, aber Sie können davon ausgehen,
es geht genau nach dem Schema,
das für das Objektsystem bekommen,
indem wir einfach ein paar Special Form schreiben und diese Special Reforms mit Death Makro oder die feinen Syntax,
wie es in Recket vornehmer geschehen kann.
Wir können... Mit diesen Erweiterungen habe ich ihnen das Brüllock gebaut,
einfach mit zwei solchen Special Forms, es hört und Anfrage.
Und damit hatten wir eine völlig neue Programmiersprachenwelt. Wir haben die Ströme,
der imperative Programmierstil ist angebaut und jetzt können wir noch mal
ein bisschen drüber nachdenken, wann benutzen wir denn den Imperativen eigentlich?
Bisher hieß es ja immer nur, Igitticit lassen wir es aus.
Aber an welchen Stellen brauchen wir es? Und das ist dann,
wenn wir bestimmte Dinge machen wollen, die einfach effizienter sind.
Und einen Weg dahin, wo wir ein bisschen imperativ werden sollten,
ist zum Beispiel bei Funktionen, die sehr viel Mehrfachaufrufe haben,
das so zu machen, dass wir da sparen können.
Ich denke, einige von Ihnen haben das jetzt schon in
den Übungen gesprochen, als es auf dem Übungsblatt geht,
aber schon wird uns das jetzt so mal gemeinsam an.
Worum es geht, ist das Grundverfahren-Caching, ja?
Also es macht ja wenig Sinn, dass man Werte, die man mehrfach braucht, mehrfach berechnet.
In den funktionalen Sprachen wie Heskel und Miranda gibt es eine Technik,
dass man Die Stellen, an denen Varianten,
Argumente mehrfach gebraucht werden,
dass man die in eine vernetzte Datenstruktur ablegt, sodass klar ist,
wenn ich sie an einer Stelle einmal berechnet habe,
dass ich, wenn ich jetzt nach dem Expandieren des Codes feststelle,
ich brauche den Wert dieser Variablen wieder,
dass ich das dann vermeiden kann und die alten Werte nehmen.
Aber generell können wir in jedem Fall, wenn wir etwas programmieren und sehen,
wir brauchen es mehrfach, einfach sagen, okay,
dann weiß ich den Wert einer Variablen zu,
speichern wir das.
Und wenn es später gebraucht wird,
hole ich ihn von da
Das Schöne, das kann man zu Fuß programmieren,
man macht solchen, eine Hash-Tabel oder so etwas, ja.
Und sucht dann in dieser Hash-Tabel,
habe ich für diese Funktion den Wert schon mal berechnet.
Und wenn nüchtern rechne ich ihn aus und speichere ihn.
Und wenn ich ihn noch nicht habe, dann,
wenn ich ihn schon mal habe, dann nehme ich den alten Wert.
Memoisation, das ist jetzt die Methode,
dass wir unseren Funktionen automatisch so transformieren lassen,
dass sie keinen Wert zweimal berechnen.
Und das können wir eben sehr gut machen,
wenn wir es zulassen,
dass wir in Recket Imperativ programmieren
Ja. Also der absolute Killer, der einen Grechenzeit in die Höhe treibt.
Der ist jetzt zum Beispiel die naive Definition der Fibunachi-Zahlen.
Aber weil das mathematisch so definiert ist,
möchte man es eigentlich ganz gern so in seinem Programm schreiben.
Dann sieht jeder Mathematiker sofort, ach ja, das sind die Fibunachi-Zahlen,
die Enlifibunachi-Zahl ist die Summe aus der N-1. und der N-2.
Und wir müssen uns noch verankern mit N,
ich bin Nacci von Null, ist Null und von 1 ist 1.
So kann man es gut lesen. Aber wenn man Rechenzeit sparen will,
ist, dass der absurdeste Weg und wir hatten ja auch schon gesehen,
wie wir über das Einführen eines Okkumulators das Ding linear rekursiv kriegen.
Die Mehrfachberechnung uns nochmal angeguckt, selbst schon für Figur Napsy 5,
die Bernatcy von drei rechnen wir zweimal aus, wie Bernatcy von zwei,
dreimal, Figur Napsy von eins müssen wir fünfmal ausrechnen und von null.
Dreimal, ja. Das ist also ziemlich unangenehm. So,
wie kriegen wir jetzt eine Funktion in eine Memo-Funktion gewandelt,
die all das nicht mehrfach berechnet
Belegen eine Tabelle für die schon berechneten Funktionswerte an.
Und wenn die Funktion jetzt aufgerufen wird,
dann prüfen wir, ob wir denn Funktionswert schon haben.
Dafür brauchen wir eine Datenstruktur. Ich tue hier mal so,
als wäre das effizient implementiert, aber ich mache es ziemlich brutal.
Ich schmeiße das einfach in eine Assoziationsliste rein.
Das ist nicht sonderlich effizient. Stellen Sie sich bitte vor,
dass Herr Mann das vernünftig programmiert hätte,
dass an der Stelle ein Mail Cash wäre,
um eine Hesh-Tabelle anzulegen und dass man dann das mit Store-Hash in Get-Tash wieder rausholt.
Okay, also wir legen es erstmal,
weil wir es so kennen, in die Assoziationslisten,
weil wir die auch noch ein bisschen üben sollen
Gut, also wenn wir dir einen Wert schon finden,
dann geben wir als Resultat zurück, andernfalls berechnen wir den Funktionswert und speichern ihn.
Und dann müssen wir als letztes noch den Namen unserer Funktion an die neue Memo-Funktion binden.
Also den Namen ersetzen. Okay. Also das Schema,
wir erzeugen irgendwie eine Tabelle, wo wir die Werte speichern,
haben eine Funktionsstore, die es in der Tabelle ablebt,
landenbar, vielleicht kriegt das Argument und den Wert,
dann nur die Trief holt für dieses Argument den Funktionswert,
dann müssen wir Milk Table definieren.
Wie gesagt, werde es für den Anfang,
der schlichtweg einfach so eine Assoziationsliste nehmen.
Ja, und dieses Entschuheball, das ist jetzt der Kern,
der macht Folgendes. Er erzeugt eine Funktion. Ja,
ein schuher Ball ist eine Funktion hier.
Sehen wir, beginnt mit Lamda, hat ein Argument X.
Und wenn das X schon bekannt ist, dann wird Metroidrief es geholt.
Ja, Fleet Trief X, also wir kriegen da den
gespeicherten Wert zurück. Und wenn der nicht Lehrer ist,
dann geben wir den Lehrer den Wert zurück.
Andernfalls rufen wir
die Funktion F auf.
FL von
Und verwenden unser Store hier oben und speichern es.
Und das Schema, was uns die Memo-Funktionen zurückgibt,
also die neue Funktion, die nicht alles zweimal rechnet,
ist, dass wir stattdessen unserer alten Funktion FN,
die wir hier übergeben haben, die neue nehmen,
die heißt Entschurwall.
Blöder Name, aber so heißt es in jedem Lehrbuch.
So, die Tabelle, die legen wir jetzt als Assoziationsliste
an. Also wir schreiben eine Funktion Memo,
der geben wir irgendeine Funktion, die sehr aufwendig ist.
Viel Rechenzeit braucht für bestimmte Werte. So,
machen hier unser Laptrick. Die Tabelle ist zuerst leer.
Die Funktion Lamda jetzt mit
Billigvariante mit Assoziationsliste. Die kriegt das Dorf, kriegt das Argument.
Also wir sagen, da bittet uns jemand Sinus von Zähnen auszurechnen.
Als FN wird 10 übergeben, das Argument ist 10.
Und das hier bekommt jetzt also das Argument 10 und
den Wert, den die Sinusfunktion zurückgegeben hat.
Und hier wird es jetzt wirklich imperativ. Wir müssen in
der Tabelle den Wert einfragen und das machen wir mit Z. Table
wird geändert auf Konz arg und Ball wird am Anfang der Tabelle eingetragen.
Und dann haben wir das. Die Funktion oder die Trief
Die sucht einfach mit Assoc in der Tabelle nach dem Argument.
Und wenn da was zurückkommt, ja, dann liefern wir
den Kütter von dem Eintrag in der Tabelle zurück.
Andernfalls sagen wir Falls, ja. So,
damit haben wir als Ergebnis eine neue Funktion, nämlich dieser Lamdeausdruck hier,
der zurückkommt, ist die neue Funktion, die zurückgegeben wird.
Und wir sehen, die funktioniert natürlich nur,
weil sie eine Closure ist,
weil in ihrer lokalen Bindungsumgebung gibt es diese Tabelle,
die bei jedem Aufruf modifiziert wird.
Also wir kriegen hier mit diesem Lamde zurück,
die in ihrer Bindungsumgebung die Tabelle hat, die wir hier eingeführt haben.
Und diese Tabelle lebt so, lange wird diese Funktion hier unten nicht vernichtet wird.
Okay. Ja, jetzt wollen wir also unsere Fibanachi zahlen,
die ja so endlos rechnen, eine Memo-Funktion verwandeln.
Und da rufen wir einfach auf. Also die neue Fibanachi-Funktion,
Memofip, ist das, was Memo zurückgibt, wenn wir die Fibanachi-Funktion übergeben.
Wir rufen es auf, Memofip von 3 und kriegen die 3 zurück.
Also die Funktion tut es ganz offensichtlich. Wenn wir uns
jetzt mal einen Trace anschauen und wollen mal gucken,
ob wir mehrfachberechnungen vermeiden konnten, Dann sehen wir,
das hat man noch nicht so ganz erfolgreich, ne?
Warum? Wir rufen hier Memo Phipp auf mit dem Argument 3.
Pibanachi Zahl 3 ist ja die Summe der zweiten und der
ersten Hypernatschi Zahl. Ruft Fipp von 2 auf,
Tipp von 2 braucht die Summe aus der ersten und der Nulten.
Ja, hat das Ergebnis 2. Aber hoppla,
hier wird Fipp von 1 wieder aufgerufen.
Das haben wir hier oben schon mal berechnet. Und das wird
hier trotzdem wieder aufgerufen, obwohl wir doch diesen Memos-Deck haben.
Warum eigentlich? Dann kommt das Ergebnis 3 zurück und
wir haben drei
Gut, also in der Rekursion klappt das noch nicht so ganz.
Aber wenn wir jetzt ein zweites Mal mehr Morphip aufrufen mit drei,
dann kriegen wir zurück sofort die drei und der Tres macht keinen einzigen Aufruf mehr.
Der Teil hat geklappt. Warum hat es in der Rekursion nicht geklappt?
Gucken wir uns nochmal an, was wir hier programmiert haben.
Dieses, die Funktion Memo, die unsere Funktionen erzeugt,
die kriegt eine Funktion FN übergeben und das ist Phipp.
Und die ruft hier unten in der Rekursion Und wenn es
den Wert berechnen soll, da ruft es tatsächlich das Phipp auf hier.
Das ist mal die richtige Stelle gehen. Also es übergeben wird Phipp,
das soll in eine Memo-Funktion verwandelt werden,
aber hier unten ruft es nicht, unser Memo-Phipp auf,
sondern die Phippanachi-Funktion, die wir in eine, ja,
Memo-Funktion gewandelt haben.
Also was wir noch erreichen müssen,
dass wir unten die richtige Funktion aufgerufen wird. Die,
die wir wirklich haben wollen, nämlich unsere Memo-Funktion,
damit die Rekursion auch immer und auf jeden Fall
die richtige Funktion
Aufruft. Und das kriegen wir jetzt wirklich hin, indem wir brutal imperativ werden.
Wir ändern schlichtweg den Eintrag in die Symboltabelle für das Symbolfip.
Wir greifen hier zum Set Banghammer und sagen,
nachdem wir fippen in eine Memo-Funktion gewandelt haben,
da ändern wir schlichtweg die Namensbindung des Symbols Fip und setzen es auf unsere neue Memo-Funktion.
Und danach wird in der Rekursion Ja, ganz brutal.
Anstelle des alten Phipp unser Neues aufgerufen. Das findet immer noch das originale Phipp,
weil das ja in dem innersten Umgebung tatsächlich noch existiert,
sonst könnten wir es überhaupt nicht mehr aufrufen.
Aber durch diesen Trick kriegen wir in der Rekursion,
die es hin, dass bei jedem Aufruf tatsächlich Mimorphipp aufgerufen wird.
Also auch die rekursiven Aufrufe gehen jetzt an die Memo-Funktion. Also was für dich Memoisation erreicht haben,
ist, dass der erste Aufruf mit irgendeinem Argument von Phipp,
was normalerweise eine Baumrekursion macht,
man berechnet die Fibonetzi die Summe aus der Fibonacci zahlt N-minus 1 und N-minus 2,
dass das eine schlichte, lineare Iteration wird,
Phipp von 4 kennen wir noch nicht,
jetzt rechnen wir erstmal drei aus, rechts,
ich will zwei auswärts, rechnen wir eins aus.
Und dann Phipp von null. Und danach sind alle Werte
bekannt und es wird kein einziger Aufruf von Fit mehr erzeugt.
Wir können trotzdem alle Summen berechnen, weil wir die Werte aus unserer Tabelle kriegen.
Und wir haben also in einer schlichten linearen Rekursion hier die 5 gekriegt.
Und wenn wir jetzt Phipp von 8 aufrufen, dann ist,
wir haben ja eben gerade Phipp von 4 berechnet,
ist das auch in der Tabelle von Memofip
Er rechnet nur bis fünf, weil ab vier kennt er alles.
Ja, und wir haben ganz schnell das Ergebnis 34.
So, ich habe es mal vor ein paar Jahren als
dem Rechner noch ein bisschen langsam war.
Es ist ausgerechnet auf einer Spark 4. Tipp aufgegerufen,
schlicht zu Fuß und ohne Memo und schon mit Tipp von 40,
haben wir einen recht hohen Wert.
Und die Zeit in Millisekunden war 89, 890.
Ich habe bis 100 gerechnet, nee, eben nicht mehr.
Also da wurde es nachts und ich habe oft gegeben
Also mit der Memor-Funktion war er in 20 Millisekunden fertig,
ja, ohne Memor-Funktion, ist das nicht rausgekommen.
Und mit Memor-Funktionen könnte ich das auch für tausend berechnen, ne?
Also diese Baumrekursion, da steckt die normale Baumrekursion,
streckt schon alle Viere von sich, schon beim Argument von 100. Jedenfalls,
so viel Kaffee kann man gar nicht trinken,
dass man es auf Ergebnis warten kann.
Mit Memo können wir es auch befügt von 1000 ausrechnen.
Ja, also wodurch haben wir es hingekriegt,
dass diese Optimierung möglich wäre, indem wir Imperative Sprachelemente genommen haben.
Wir haben einmal zum Speichern in der Tabelle, haben wir ein Setbang verwendet.
Damit legen wir die Tabelle an einer bekannten Ergebnisse.
Wir hätten es natürlich zu Fuß machen können,
indem wir immer, oh Gott,
mit mehr Pens rangehängt haben und jedes Mal die Funktion neu rekonstruieren.
Aber das dauert natürlich länger, als was wir versparen.
Und wir haben die Modifikation der Referenz,
den Eintrag in der Symboltabelle, welche Funktion soll ausgeführt werden,
wenn jemand Phipp sagt,
den haben wir geändert und ist durch die Mimo-Funktion ersetzt,
sodass alle rekursiven Aufrufe
auch dahin gehen
Und damit haben wir es geschafft, dass wir eine Funktion von
exponentiellem Aufwand reduziert haben, auf einen von linearer Ordnung.
Also ich will auf keinen Fall Imperatives programmieren, verdammen,
da wo es Sinn macht, sollten wir es tun,
aber wir sollten es immer gut überlegen,
denn weil es kostet es uns, wenn wir imperativ werden.
Die Bezugstransparenz ist weg. Beweise werden schwieriger und wir können
uns nicht mehr darauf verlassen,
dass die Reihenfolge Unabhängigkeit gegeben ist,
wenn wir
funktionale Ausdrücke auswerten
Deshalb nur da, wo wir uns sicher sind,
dass wir es brauchen und die Stellen gut kommentieren,
die Funktionsnamen mit einem Ausrufezeichen versehen, dass jeder sofort sieht,
Achtung, hier haben wir Reihenfolgeabhängigkeiten.
Und dann haben wir es wunderbar geschafft. Okay. Gehen wir mal
jetzt auf einen Teil, den wir noch ausgelassen haben.
Was ich noch vorhabe, ist mit Ihnen einmal noch ein Beispiel anschauen,
was ich zu Anfang schon mal versprochen hatte,
dass wir uns als eine kleine Fallstudie für funktionales Programmieren den General Problem Solver anschauen.
Der ist noch offen
Das nächste Mal, nächsten Freitag möchte ich eine Zusammenfassung der Vorlesung machen.
Also dann gehen wir den letzten Teil vom Skript durch,
wo wir die verschiedenen Programmierstile gegeneinander stellen.
Und wir werden bei der Gelegenheit es mit zugetragen worden,
dass wir es gern möchten, eine der ausgeteilten Probeklausuren besprechen.
In der zweiten Hälfte auch nochmal, wenn wir die
zweite Probeklausur besprechen, die ins Diene im Netz hängt.
Ja, also ich habe zwei Probeklausuren reingehängt und die zweite
werden wir dann am nächsten Freitag auch nochmal besprechen.
So, gehen wir mal zum General Problem Server
Das war ja eines der Timmen der Fallstudie, ne?
Also all diese Fallstudien, die ich hier in Skript eingeflochten habe,
stammen aus dem Buch von Peter Norwick,
in dem er das funktionale Programmieren in Kommendes darstellt.
Und das sind alles Beispiele, die zeigen,
wie die typischen Entwurfsmuster aussehen,
wenn wir ein größeres System rein und klar funktional entwerfen, ja?
Und der General Problem Server ist nur eines der Programme,
die erfunden wurden, in der Zeit,
bevor richtig klar war,
was der funktionale Programmierstil ausmacht
Was den ausmacht. Und deshalb finde ich ihn sehr spannend,
weil wir nämlich sehen können, welche Probleme die Leute sich eingehandelt haben,
als sie nicht rein funktional programmiert haben.
Die Vermischung von funktionaler Programmiersprache mit imperativen Elementen hat zu all
den Problemen geführt, die ich hier jetzt ansprechen werde.
Und in dem Moment, wo das Programm neu geschrieben wurde von Norweg,
rein rassig funktional waren, diese Probleme weg, die über jahrelang die KI-Konferenzen bevölkert haben.
Also das ist, von daher finde ich das so gut. Ja,
was war der General Problem Soul,
weil das ist so ein urahne der deklarativen Programmierung,
wo zum ersten Mal versucht wurde,
das Wissen über die Welt in Form von Regeln zu beschreiben,
in einer Datenbasis und dann einen Automatismus zu haben,
der die Regeln kombiniert und durch Inferenz versucht zu erschließen,
was die Lösung ist.
Heutzutage haben wir das fertigen über die Programmiersprache pro Log nehmen. Die Art,
wie nach einer Lösung gesucht wird, ist genau andersrum,
kein Problem, aber die Grundidee, wir trennen,
dass Wissen über die Fakten der Welt den, das Deklarieren der Schlussfolgerungsregeln,
mit denen wir arbeiten, was folgt aus wem?
Von dem Code, der die Suche macht. Die Suche kaufen wir fertig,
wir kaufen die Unifikation fertig, das Suchen in dieser Datenbasis.
Also genau diese Ideen sind zuerst implementiert worden,
weil dann in dem Programm General Problem Server.
Nur der Newel hat es damals eben ein so,
ja, übertriebenen Namen gewählt, ja,
wirklich mit dem Anspruch oder ist so verkauft,
ich habe ein für alle Mal aufgeschrieben, wie wir Probleme lösen,
ja, egal was das Problem ist,
nimmt mein Programm
Und die Idee beim General Problem Server war eben,
dass wir die Suche nach dem Algorithmus,
wie wir das Problem lösen können, auch dem Programm überlassen.
Wir sagen nur die Fakten, wir sagen alles,
was wir wissen und der Computer sollte so intelligent sein,
intelligent jetzt im Hinblick auf die Möglichkeit Schlussfolgerungen ziehen zu können.
Das Arbeiten mit Wissen soll er können.
Und da er das systematisch und ordentlich macht,
und da brauchen wir gar nicht konzentriert drüber nachzudenken,
wir sagen nur all die Fakten und das Programm
sucht uns
die Lösung
Genauso verwenden wir heutzutage pro Lock. Wir tragen alles zusammen
, was wir über ein Problem wissen. Versuche es schon
ein bisschen zu strukturieren, weil uns ein Lösungsweg vorschwickt.
Aber letztendlich wird Unifikation und Suche in Pro-Lock bei dem gebündelten Wissen
dann uns sagen, ja, es ist lösbar oder nicht.
Und es ist lösbar, wenn wir die Variablen so binden.
Ein ähnlicher Ansatz hatten wir beim General Problem-Solver,
also dem Computer nicht mehr als dummen Rechenknecht zu nehmen,
sondern wir programmieren eben das Denken.
Das war die Idee. Weg vom Mythos des dummen Computers
. Und dieser dumme Computermythos,
der ist übrigens nicht eine Erfindung der KI in den 50er Jahren,
sondern das ist schon von Lady Eda Lafles so gesagt worden.
Schon die hat als Charles Babic seinen ersten Computer gebaut hat,
nee, den zweiten, die Analytical Engine.
Und sie hat für diesen die ersten Programme geschrieben,
hat sie gesagt, dass die Grenzen längst nicht erkundet sind.
Wir müssen ihm nur, also alles, was wir sagen können,
wie es gemacht wird, wird er können.
Wir müssen nur den Weg finden, das als Programm zu beschreiben.
Gut, trotzdem hat man immer gesagt,
der Computer ist der Dumme, der macht als Maschine einfach das,
was die Programmierer ihm sagen.
Und die Schlauen sind die Programmierer
Dieser Schritt hier war, wir sagen,
wir programmieren den Computer schlau zu sein. Okay. Also,
und das problemlöse Paradigma, was eben von New El angeführt wurde,
das ging davon aus, dass auch die Suche nach dem Algorithmus,
dass die auch ein Problem ist, dass man systematisch angeht.
Und das hat er versucht, durch einen Algorithmus zu beschreiben.
Also programmieren besteht daran, möglichst genau das Problem zu beschreiben.
Der Rechner sucht systematisch nach Lösungsmöglichkeiten. Und ja,
diese Zitate hatte ich ihn schon mal vorgelesen
So, die Vision von GPS, aber wirklich,
das einzige Programm, ein einziges Programm,
das jedes Problem lösen kann, wenn es überhaupt lösbar ist.
Toll. Ja, macht uns arbeitslos. Also, wenn
das auf dem Markt ist, können wir einpacken. Also,
wir können ganz froh sein, dass es seit den 50er Jahren,
wo diese Ideen aufkamen, nicht gelungen ist.
Also auch der General Problem soll bei GPS halt diese Erwartung
nie erfüllt. Aber es war ein ganz wichtiger,
weil Meilenstein der Informatik, weil es war das erste Programm,
bei dem tatsächlich das Wissen über den Problembereich und problemlöse Strategie
getrennt wurde
Und damit war es auf eine Vielzahl von Problemen anwendbar.
Und es hat das Forschungsgebiet Wissensrepräsentation begründet. So,
das klassische Beispiel von Ellen New Müll,
das hatten wir das letzte Mal schon angesprochen,
wir wollen das Kind zum Kindergarten sagen.
Was GPS versucht hinzukriegen, ist den Unterschied zwischen dem,
was wir erreichen wollen.
Und dem, was wir zurzeit haben, zu verringern.
Also, wenn das Kind zu Hause ist,
es soll ja beim Kindergarten sein, ist der Unterschied die Entfernung.
Jetzt suchen wir noch etwas, was die Entfernung verringert.
Und dazu kann man zwei Dinge tun,
entweder laufen oder fahren
Wenn suchen, was haben wir? Wir haben das Auto
. Ja. Oh, das Auto ist aber kaputt.
Was brauche ich damit, das Auto eingesetzt werden kann?
Eine neue Batterie. Wie komme ich zu einer neuen Batterie
und so weiter? Und dieses Dimens end Analysis. Das
ist es, was wir wollen. Schön, reich,
gesund, jung. Das, was wir sind, versuchen,
was kann den Unterschied verändern? Vielleicht kann man im Reich
was tun, indem man arbeitet und Geld verdient.
Und andere Möglichkeiten. Also das nennt sich die Means Ends Analysis.
Also welche Mittel zum Zweckanalyse, welche Mittel habe ich den
Zweck zu erreichen und das ist ein GPS eingebaut worden.
Zu suchen, welche Mitteln hat mich, damit ich das Ziel erreiche.
Ist von Aristoteles schon so oft geführt, of course,
this kind of analysis is not exactly you.
The theory of means ends analysis was late down quite allergently by artist total,
2003 100 years early and the chapter and titled,
the nature of deliberation and it's objects of the Nico Machine Ittics.
Also, Aristoteles hatte als Philosoph auch darüber schon nachgedacht,
welche Mittel zum Zweck wir haben.
Er hat noch ein bisschen Ethik mit reingebraucht,
das ist nicht jedes Mittel, jeden Zweck rechtfertigt.
Gut, aber das ist, habe ich im Pro-Log nicht gesehen,
dass da Regeln über ethisches Anwenden waren.
Gut, also die Phase 1 ist erstmal, wir müssen unser Problem beschreiben.
Wir besuchen ein allgemeines Verfahren, das Unterschied beseitigen kann zwischen dem,
was ich habe und dem, was ich wünsche.
Und das Resultat sollte eine Liste von Aktionen sein,
die ausführbar sind. So, es ist ein Problem,
manche Aktionen sind nur ausführbar, wenn Vorbedingungen erfüllt sind.
Und dann kommen wir zur Rekursion. Wir versuchen rekursiv für
die Aktionen, die zum Ziel führen, die Vorbedingungen herzustellen.
Also wir wollen, wir haben festgestellt, das einzige,
was das Kind zum Kindergarten bringen kann, ist das Auto,
aber Auto fährt nicht.
Ich versuche, die Vorbedingung zu erfüllen, dass es fährt.
Das heißt, ich versuche dem eine neue Batterie zu geben.
Und wir können ein Problem als gelöst betrachten,
wenn es direkt anwendbare Operationen gibt, das Ziel erreicht.
Oder wenn andere Aktionen die Vorbedingungen sicherstellen, damit solche Aktionen anwendbar wird.
Und wenn wir für diese anderen Bedingungen, die Vorbedingungen wiederum herstellen können.
Und dazu brauchen wir auch wieder eine Datenstruktur,
die uns sagt, was die anwendbaren Aktionen sind.
Ja, für jede Aktion beschreiben,
das ist die Vorbedingung und was ist die Konsequenz dieser Aktion.
Wie verändern Sie den Zustand der Welt? Und das heißt,
wir repräsentieren Ausgangszustand und Zielzustand als Liste von Bedingungen.
Und dann ist unsere Vision,
dass wir einfach den General Problem-Solver aufrufen,
indem wir sagen,
was sind die bekannten Vorbedingungen
Was sind die, was ist der Zustand,
den wir jetzt haben? Was ist der Zustand, den
wir wollen? Und wir übergeben eine Liste von Operationen,
die hoffentlich dazu führen, von hier nach hier zu kommen.
Und aus dieser Liste von Operationen sucht der General Problem Zoll,
weil die Sequenz aus, die möglich ist.
So. Ja, um das programmieren zu können,
haben wir erstmal eine Stützfunktion Find All im Tools Module.
Das guckt einfach nur eine Liste von Bedingungen durch und in
einer Sequenz
Das Liste und wendet einen Test an. Ob der Test
erfüllt ist. Und genauso ein Find all not,
filtern, es findet in der Liste der Sequenzen alle,
die es nicht erfüllen. Da verwenden wir die höhere Funktion,
die geht, die ein Prädikat umdreht.
Ansonsten macht es dasselbe wie das da oben. Gut,
die Operation, die definieren wir einfach als Instructure, die feinen ab.
Das sagt ja Namens, Action, Pre-Condition,
es hat eine Adlist und eine Dallas,
was damit gemeint
Wenn diese Aktion ostgeführt wird, wird erst mal geguckt,
so die Vorbedingungen erfüllt, wenn sie erfüllt sind,
dann steht hier, was sie am Zustand der Welt
ändert und was sie an Vorbedingungen der Welt zufügt.
Ja, und das ist das, was dann noch nicht mehr gilt. Zum Beispiel,
wenn diese Aktion dazu führt, dass ich Geld ausgebe,
wird aus dem Zustand der Welt das Geld entnommen,
was sie ausgegeben hat, das habe ich nicht mehr.
Wenn es eine Aktion ist, wo ich Geld verdiene,
kann ich, wird dem Zustand der Welt zugefügt,
dass ich jetzt Geld habe, wenn ich diese Optionen ausführe.
Und der Rahmen für GPS General Proprim Server bekommt den Zustand
der Welt, bekommt Ziele,
die erreicht werden sollen und die möglichen Operationen
So, die Operationen sind also Structures. Ja,
und wir haben dafür dann Adzessor-Funktionen. Wissen wir ja,
wenn wir in Reckett eine Structure definieren,
dann bekommen wir automatisch für alle Felder dieses Records die Zugriffsfunktionen.
Ob Action, ob Precons und die beginnen mit dem Namen des Structure-Types.
So. Dann die Ablaufkontrolle in der Funktion GPS-Genderal Proprim Soul,
weil wir übergeben den Zustand, die Ziele und die Operation.
Dann wird hier drin
eine Funktion definiert
Die versucht, das Ziel zu erreichen, die heißt Chief,
die werden wir gleich definieren und die wird trikorsiv sein.
So, und dann verwenden wir die Funktion höherer Ordnung. Every,
ja, die prüft, ob für jedes Ziel das Ad-Chief erreicht wurde,
ja, wenn das der Fall ist, geben wir Säuf zurück,
andernfalls nicht erfüllt, ja.
Also Problem ist gelöst, wenn die Funktion jetzt Chief jedes Jahr Ziele erreicht hat.
Relativ simpel. So, das Achieve Soul für irgendein Ziel,
das versuchen wir so hinzukriegen
Indem wir zuerst mal einen Kommentar ausgeben,
was wir zurzeit versuchen, Whiteline, List treilen.
Und dann kommt das Ziel. Ja, das Ziel ist erreicht,
wenn es schon ein Element ist, das augenblicklichen Zustands des Date.
Der Zustand unserer Welt, wenn das Ziel drin ist,
testen wir mit Member, dann sind wir fertig.
Andernfalls verwenden wir die Funktion zusammen aus Kommenläss. Some ist eine Funktion,
höhere Ordnung, die wendet ein Kredikat auf eine Liste
an und gibt uns die Restliste ab der Stelle zurück,
wo wir Zum ersten Mal das Prädikat erfüllt finden.
Ja. Genau. Und dieses Sam,
das wenden wir drauf an, mit Find All, Goal,
Ops und ob dieser Operator Appropriate ist, aber das Ziel erreicht.
Ja. Appropriate ist der Test, der sagt,
ja, kann dieser Operator tatsächlich das Ziel erreichen?
So. Und Appropriate, das testet einfach, ob das Ziel,
was wir haben wollen, ob das in der Adlist des Operators steht.
Also wenn das ein Operator ist,
der heißt Geld verdienen und mein Ziel ist,
Geld zu haben, dann steht in der Adlist,
ja,
ich habe hinterher Geld
Und genau das, was mir hier mit Member getestet,
kommt es für den Operator in der Adlist vor,
dass ich diesen neuen Zustand habe.
Und wenn ja, dann wird der Operator angewendet. Also,
wir wenden den Operator an, wenn tatsächlich alle Vorbedingungen
des Operators erfüllt sind, dann können wir ihn anwenden.
Wir schreiben einfach raus, Executing, die Aktionen des Operators.
Und ja, wir sind jetzt genau an der Stelle,
wo ich sage, alle Schwierigkeiten von GPS kamen daher,
zu dem Zeitpunkt der funktionale Programmierstil noch nicht richtig verstanden war.
Und die ersten Implementationen in der funktionalen Programmiersprache ständig mit Z-Bang imperativ programmiert haben.
Wir sind genau an einer solchen Stelle und diese Stelle wird
sich später rächen. Was nämlich das Achieve Goal macht,
das nimmt den Zustand der Welt und berechnet funktional sehr nett,
die Unterschied zwischen den beiden Listen mit Z-Differenz,
also die Mengendifferenz, der Bedingungen, die wir haben,
der wird berechnen und der Zustand wird gesetzt auf die Differenz zwischen dem Zustand und der Delision List des Operators.
Das heißt, also das,
was nach dem Geldausgeben nicht mehr gegeben ist, wird weggenommen.
Und hinterher wird es aber die Set Union genommen und es wird geguckt,
ja, was habe ich dafür dazu gewonnen, ja?
Das ist aus der Delision List wird rausgenommen,
das ist was in der anderen Liste rausgenommen.
Der Zustand der Welt hat sich verändert. Also das Apply-Op bei
der Suche nach der Lösung verändern wir eine globale Variable,
die den Zustand der Welt beschreibt, ne?
Also das allererste berühmte Listbuch, wo erklärt wurde,
wie programmiere ich in Funktionalen Programmierstil, ja? Zehn Jahre,
nachdem es veröffentlicht war, hatte ich das in die Hand gekriegt.
Und dann hat sich der Magen umgedreht. Also es ist genauso geschrieben,
man sich vorstellt, das Forttrennprogrammierer ein Lisplayer-Buch schreiben, ja?
Kein Wunder, die Leute, die diese Bücher geschrieben haben
und zum ersten Mal mit der Sprache arbeiten sollten,
die sind groß geworden mit dem reinen imperativen Programmierstil.
Und die haben wirklich gnadenlos in der schönen Sprache Lisp erfordern programmiert.
Und aus, dies ist in der Zeit geschrieben,
sogar bevor es kommendes gab, also es sei ihnen verziehen,
ja, aber Hier ist die Suche so realisiert.
Wir haben einen globalen Zustand der Welt, suchen nach Vorbedingungen und so weiter,
wenden die Operatoren sofort an, verändern sofort den Zustand der Welt,
wenn wir gefunden haben, dieser Operator kann das.
So. Und was wir hier zum ersten Mal sehen,
ist eine wirklich schicke, indirekte Rekursion zwischen Apply,
Op und Achieve, ne? Also wir haben gesehen,
die Funktion Achieve, die versucht ein Ziel zu erreichen,
in dem es solange Operatoren Apply Op anwendet,
bis mindestens einen Aufruf erfolgreich war.
Das ist die höhere Funktion Sam, die wir gesehen haben.
Wenn Sie jetzt die Definition von Apply angucken,
die ruft ihrerseits atchief auf, ja, bevor ich einen Operator anwende,
muss ich dafür sorgen, dass er anwendbar wird.
Und das machen wir hier, indem wir die Vorbedingungen testen
oder versuchen, sie zu erfüllen. Also der,
wir müssen erreichen, dass die Vorbedingungen wahr sind,
erfüllt sind, bevor wir ihn anwenden können.
Und dieses Achieve, das sucht aber wieder mit Apply,
ob nach Operatoren, die es machen.
Also wir haben hier eine herrliche,
indirekte Rekursion
Eine indirekte Baumrekursion. Bei der werden Abwechsel oder nur alle oder
nur einen Knoten bearbeitet. Was wir damit eigentlich tun,
ist ein Klassiker aus der künstlichen Intelligenz.
Das sind die und oder Bäume. Wir haben immer eine Ebene,
bei der geguckt wird, was kann ich jetzt tun?
Auf der, wenn ich einen Accif suche,
dann suche ich nach Operatoren, die es können und suche,
versuche irgendeinen Operator zu finden, der direkt anwendbar ist.
Das ist die It's schiff-Ebene, die haben wir hier zum
Beispiel, ja. Also ich will diesen Opparator anwenden,
da müssen sämtliche Vorbedingungen erfüllt sein, sämtliche. Das heißt,
ich habe eine Unebene und das zeichnen wir und oder bauen durch diesen Grindel hier.
Der sagt, alle, diese Bäume müssen ein gutes Resultat geben.
Wenn ich jetzt die erreichen will, dass dieser Baum erfüllt ist,
jetzt bin ich in der Oder-Ebene, ich kann dies,
dies oder das verfolgen,
da müssen wieder mit uns alle erfüllt sein und so weiter und so weiter.
Immer eine Schicht mit oder eine Schicht mit uns.
Gut, und jetzt kommen wir nochmal wieder zurück,
wie kriegen wir unsere Kinder in den Kindergarten
Und schauen das direkt bei einem BGPS, das gemacht hat.
Wir definieren jetzt unsere Domänen spezifischen Operatoren und wollen also
einen Operator haben, fahre das Kind zur Schule.
Heißt Drive Santo School, also das ist unser kleiner Junge,
Operator, Drive Santo School, das ist die Aktion.
Damit ich in zur Schule fahren kann, muss er zu Hause sein.
Also Vorbedingung ist, er muss zu Hause sein.
Pech ist, wer da schon in der Schule ist,
dann kann ich diese Operation nicht anwenden. Zweite Vorbedingung ist,
dass das Auto fährt, was sich erreicht in der Utlist,
das ist dass das Kind in der Schule ist und was
es hinterher nicht mehr ist, es ist nicht mehr zu Hause.
Angenommen, dass Schule und Zuhause unterschiedliche Plätze sind, ja.
Okay. Und ja, das Auto fuhr ja nicht,
also wir müssen irgendwie dafür sorgen, dass es fährt.
Wir können, also ein, da die Batterie fehlt,
können wir gut eine Operation gebrauchen, Shop in Stalls Battery,
ja, Vorbedingung, dass er das macht.
Das nenne ich Optimismusmus. Also wenn wir ein Auto zur,
in die Werkstatt fahren und sagen, ich brauche eine neue Batterie,
da gehen in diesem Programm davon ausgegangen,
dass sie die Batterien nicht neu installieren,
wenn es schon eine Batterie hat die Fährt,
die gut geeignet ist, ja.
Also, hm, kam nichts Batterie, muss gegeben sein als Vorbedingung.
Ja, und die Werkstatt muss auch wissen, shop nur's problem.
Das weiß, dass die Batterie ausgewechselt werden muss.
Und die Werkstatt erwartet Geld, ja.
Gut. Das sind also die Vorbedingungen. Ich muss der
Werkstatt Geld geben, dann macht es das Erstzahlen.
Dann wird gearbeitet, ein bisschen Mensa-Technik.
Nach Bedingung ist, dass das Auto widerfährt, ja.
Und auf der Delete-Liste ist,
dass das Auto
keine Batterie mehr braucht
Das ist ja ein optimistischer Artist zu modellieren. Gut. Ja,
wie kann ich der Werkstatt mitteilen, dass das Auto repariert werden muss?
Vor Bedingung ist, dass sich irgendwie eine Kommunikation herstelle.
Und die kann ich zum Beispiel herstellen, indem ich die Werkstatt anrufe.
Dass die Vorbedingung, dass ich die Telefonnummer weiß.
Damit ich die Telefonnummer rauskriegen kann, brauche ich ein Telefonbuch.
Und Giftshop Money, dann hat der Hisel hinterher in
dem Zustand, dass er Geld hat. Okay,
also mit diesen Regeln, wenn wir genau die Regeln eintragen,
rufen oder ein General Program Säulver auf.
Was kriegen wir? Eine lange Folge Executedin. Aha,
ich muss zuerst die Telefonnummer nachschlagen. Dann erfahre ich,
musste Werkstatt anrufen. Dann muss ich der Werk,
wenn ich mit ihr rede, ihr mitteilen,
dass das Auto eine Batterie braucht.
Dann gebe ich der Werkstatt mein Geld. Der laden die Werkstatt
installiert die Batterie. Und ich kann mein Kind zur Schule fahren.
Und säuft. So ungefähr. So, das ist eines
der ersten Beispiele aus dem General Program Säulver, wir uns die Lösung gibt. Wenn wir die Vorbedingungen nicht so günstig sind,
dann kann es schief gehen, also wenn die Vorbedingungen sind,
das Kind ist zu Hause,
das Orte braucht eine neue Batterie und ich habe Geld,
Ziel ist Kind in der Schule mit den Operatoren,
Try and Sunded School, Sanato im Carworks Carnets Battery,
Shopnos problem, Try and in Communication This Shop,
no full number, schreie her fun, bock,
da geht es schief,
wir haben kein Telefonbuch.
Kommt zurück, not salft. Weil wenn ich modelliert habe,
wie mein Telefonbuch auftreibt. Dagegen Wenn das Out of schon fährt,
dann ist es ganz dritt wieder eine ganz kurze Liste zurück und sind fertig.
Kind ist in der Schule, ja? Also dieses Verfahren,
das sieht relativ simpel aus und ehrlich gesagt,
das war es ja auch, ne?
Es wendet eigentlich nur Wissen an, was wir ihnen mitgegeben haben.
Insofern müssen wir selbst schon tatsächlich viel dazu beitragen, dass das Problem lösbar wird.
Aber das sind vier harte Beschränkungen, die kann man,
wenn man sehr hart ist, auch Bugs nennen, ne?
Und dann anschließend haben wir so eine etwas bessere Version an,
die einige dieser Bugsen nicht hat, ja?
Also eines der dicken Probleme ist, wird bekannt geworden,
hätte dem Namen Running Around the Block problem.
Was ist damit gemeint? Der General Poplip-Sumpsolver, der wird nie
eine Aktion ausführen, die den Zustand der Welt nicht verändert.
Wir müssen alles so programmieren, da ist ja Zustand der Welt verändert wird.
Wenn wir einfach nur so zum Vergnügen jeden Morgen eine Stunde einmal um die Alster rennen,
dann sind wir hinterher wieder im gleichen Ostgangsort und diese Operation,
dass man morgens erstmal einmal um die Alster läuft,
die wird einfach nicht ausgeführt, weil es kein Ziel ist,
wenn das nicht explizit modelliert haben,
dass unser Ziel zum Beispiel ist,
ein Kilo leichter sein oder so irgendetwas
Also das heißt, is it running around the prop,
block problem, wenn wir etwas tun wollen, nur damit es getan wird.
Das geht nicht. Also GPS kann keine Operatoren anwenden,
die nicht den Zustand der Welt verändern.
Also für einmal um die Alster joggen,
wer die Adlist und die Leadlist dieselbe oder sind leer.
Und als Vorbedingung vielleicht, Herr Franding Shoes,
Nizzam Accessize, wenn Add und die Leadlist leer sind,
dann wird das nie ausgeführt.
Das andere ist, bekannt geworden wird in dem Namen,
kloppert Sipplink
Siblings-Problem. Keilerei verwandt der Ziel, habe ich
es mal auf Deutsch gesagt. Und das Problem meint,
wenn wir Vorbedingungen haben und wir können mit einer dieser Vorbedingungen
Ziel 1 erreichen, wir könnten damit Ziel 2 erreichen.
Beide brauchen dieselbe Vorbedingung und entfernen die Vorbedingung. Wenn wir das eine Ziel erreicht haben,
ist es weg und die andere kann es nicht ausführen,
ja, weil wir sagen, wir haben Geld,
geben es aus, um das Auto zu reparieren,
dann haben wir kein Geld mehr,
um unser Kind ein Eis zu kaufen.
Wenn wir zuerst das Eis kaufen, haben wir kein Geld für die Batterie.
Und diese Keilerei der verwandelten Ziele, die sind Vor allem dadurch gegeben,
dass wir den Zustand der Welt sofort ändern,
komplett ändern in der globalen Variablen, ja, der steckt da eigentlich hinter.
So, sagen wir mal, wir wollen das Kind zur
Schule bringen und hinterher noch Geld übrig haben, ja.
Thundert tom have money carworks, nach das Ziel have money
on sunnit school, ja. Wenn wir das Kind zur Schule fahren,
dann kann es uns passieren, dieses Ort,
der erst repariert werden muss, dass das Geld weg ist,
aber GPS so tut, als wäre es trotzdem gegeben,
hat das Geld immer ausgegeben für die Batterien, ne?
Ja. San der Turm Carnlets Battery,
wenn wir da das Geld haben und Heaven Money ist unser Ziel,
dann würde GPS folgendes machen. Telefonnummer nachschlagen, Tippen,
Werkstatt anrufen, sagen, ich brauche eine neue Batterie,
das Geld ausgeben für die Batterie. Die Batterie wird installiert,
wir fahren das Kind zur Schule und die erste Version von GPS,
so wie sie veröffentlicht ist, würde dann sagen,
das Ziel ist erfüllt, aber wir haben gar kein Geld mehr.
Wir haben alles für die Batterie auf den Kopf gehauen,
Das geht also nicht. Stimmt. Also man kann das
natürlich jetzt modifizieren, ist dann auch gemacht worden.
Und wir müssen hinterher beim Achieve Goal noch nachgucken,
ob wirklich jedes unserer Ziele immer noch eine Teilmenge vom Zustand der Welt ist.
Subset Goals State. Wenn wir das so machen,
also diese Überprüfung aller Teilziele, dann geht's gut.
Gut. Und der Liebling before the look problem können,
das ist Oh, habe ich das überhaupt erklärt?
Ja, der Liebling before the look problem,
das ist jetzt wirklich eine ganz dicke Konsequenz dessen,
dass wir imperativ programmiert haben. Es ist so,
dass jeder Operator, wenn er getestet werden soll,
ob er anwendbar ist und zum Ziel führt,
dass der gleich den Zustand der Welt verändert.
Also die Vorbedingungen Ja, die Adlist und die,
die Leadlist werden genommen und dann wird geguckt, hinter,
ja, der Operator ist anwendbar,
also wenden wir ihn sofort an und Add und die Leadlist verändern den Zustand der Welt.
Und wir kommen, bekommen in diesem Fall,
wenn die Methoden der verkehrten Reihenfolge ausprobiert werden,
leider falsche Lösungen. GPS hat alle Operationen ausgeführt,
um das erste Ziel zu erreichen und dann stellt er fest,
dass das zweite Ziel nicht erreicht werden kann.
Das brutalste, die brutalste Art wäre,
Ich möchte von einer Klippe springen, aber sicher unten ankommen.
Also die GPS wird erstmal sagen, ja,
die Vorbedingungen sind da, wir können springen und erst am Ende gucken,
ob wir dann auch sicher landen.
Das ist ungefähr dies hier, ja. Wir stehen an
der Klippe, haben vielleicht Musik und so weiter. Wir sind dabei,
zu springen und haben noch nicht drüber nachgedacht,
wie wir unten sicher landen können, weil das erst geprüft wird,
nachdem der Zustand der Welt verändert wurde.
Ich kann mich erinnern, Dass ich beim Skilauf mal mit einem Anfänger unterwegs war.
Und der ist mir sofort hinterhergefahren. Und mitten in der Schussfahrt
den Abfang runter fragte. Und übrigens die Bremsband mit Skiern,
aber der war inzwischen so schnell.
Ich konnte sie nicht mehr sagen. Und das war also
keine so gute Idee. Gut. Das andere Problem ist
der Recurns of Subgirl-Problem, ja. Wenn wir eine Situation haben,
in der wir immer wieder rekursiv dasselbe testen, kriegen wir auch ein Problem.
Wir könnten die Telefonnummer von der Werkstatt rauszukriegen,
auch die Werkstatt anrufen
Das wäre eine gute Idee. Also man kann nicht nur am Telefonbuch nachschlagen,
man könnt auch anrufen. Also wir könnten hinzufügen,
Arskforn Number in Communication, The Shop, das ist die Nachbedingung.
Wir haben danach die, wenn die Vorbedingung, wir müssen,
um fragen zu können, müssen wir die Kommunikation haben.
Und hinterher kennen wir die Telefonnummer. Wenn wir das machen,
dann kriegen wir Segmentation Falt oder wie immer die Fehlermeldung heißt, wenn der Speicher ausgeht.
In dem Fall wird eben endlos immer wieder versucht,
rauszukriegen, wie die Telefonnummer ist, damit man anrufen kann.
Und wir sind in einer schönen Endlosschleife, ja.
Wir haben uns da den Trace angucken, ja,
dann wird hier immer Trying in Communication, guckt die Telefonnummer rauskriegen,
indem man wieder versucht, in Communication zu kommen und,
und, und, und, ja.
Also, GPS in der Endlosschleife hängen geblieben, immer wieder versucht,
die Voraussetzung für das Problem selbst zu lösen, ne?
Also, die Vornehmerart, dass diese Entschlussschleife zu titulieren,
war Ostsee Lating in Mong Ends,
Functions required and Means that performed them
Also wir können natürlich, um sowas zu vermeiden, den Code so ändern,
dass wir prüfen, ob das schon mal versucht wurde.
Dann noch der Mangel an Informationen,
man kann das Programm mit, die Backausgaben spicken,
sodass man sehen kann, was zurzeit erzielt verfolgt wird.
Und da in der Version, die sie bei Peter Norweg finden,
da ist ein Mai-Debug drin und ein Andi-Bug und so,
das ist sehr schön.
Die Version 2, die ändert nicht den globalen Zustand,
sondern führt eine eigene Zustandsvariable ein.
Das verhindert das Liebling,
before you look problem
Es gibt eine Liste der aktuell verfolgten Ziele zurück.
Und da haben wir einen Stack. Und da können wir auch schauen,
ob da so eine Oszillation zwischen Zielen drin ist.
Und das ausführende Operation ist auch eine Zustandsänderung, ja.
Und wenn wir das separat modellieren,
dann können wir auch das Running Around The Block-Problem verhindern.
Okay. Weil ein GPS 2, in dieser Form,
da haben wir jetzt diese wunderbaren Aktionen und das klappt bestens.
Die Bagger auch, da wird immer so ein Considering,
gesagt nicht, also versuchen wir mal, ob es damit geht.
Ja, und wenn das eben nicht geht,
wird ein anderer Zweig versucht
Also es wird nicht sofort ausgeführt, sondern nur wenn
man sieht, dass das tatsächlich zum Ziel beitschreckt.
Und dann sind wir fertig. Das ist also drin. Ja,
schauen wir uns mal weitere Anwendungen an, um zu zeigen,
dass GPS 2 mehr als eine Domäne behandeln kann, ja.
Also ich habe da selbst mal ein altes Volkslied modelliert,
whole in the bucket. Sie kennen es,
als ein Loch ist im Eimer, ne?
Das berühmte Monkey and the Nenner-Problem, also hungriges Äffchen,
versucht seine Banane zu erreichen
Weg durch ein Labyrinth und die Blocksworld-Domain.
Also alle finden sie in der SE3-Bib. Gucken wir mal
, erst mal ein Loch ist im Eimer an.
Rennen Sie sich an das Lied, die doch ist im Eimer
, wenn es will, Wasser holen.
Also man möchte dann einmal reparieren. Und ich möchte einmal,
ist in diesem Lied beschrieben,
das Problem
Sehr schade. Kannst doch was reden als Englandes,
in einer Woche hohes Bauprodukte, in einem bestätigen Eindruck,
in einer Vermeidung. Das ist schon für eine neue oder neue,
oder eine neue Verständnis, bei der euch fachtet.
Jetzt sind wir mit der Englandschaft zwölf Tage, okay,
das ist ein Blut, das umgeblieben ist,
aber das ist nicht der Stroh,
das ist der Stroh
Ja, ja, ja, ja, ja,
ja, ja, ja, ja, ja,
ja, ja, ich habe hier leider keinen Fonds,
was knopfen
Und vielleicht kann es sein. Und es ist nicht
so einfach zu seiner Zeit, eine Anleitung zu sein.
Also sie haben die generelle Idee des Liedes. Wir haben
das Problem, einmal hat ein Loch Verstopfen mit Stroh.
Ja, Stroh ist zu lang. Machen wir es,
hacken wir es ab mit der Axt. Daneben,
ja, die Axt ist stumpf, müssen die Axt schärfen.
Wie kriegen wir sie scharf mit dem Stein?
Der Stein ist zu nass, ist zu trocken.
Wie kriegen wir ihn nass für hohlen Wasser?
Womit holen wir Wasser
Mit dem Eimer. Und der Eimer hat ein Loch und ist
ein Problem da. Wir können jetzt im SIPS so modellieren,
habe einmal, einmal hat ein Loch, ich habe Stroh,
Stroh ist zu lang, ich habe Stein,
Stein ist trocken, habe Axt, Axt ist stumpf,
wenn ich habe Wasser habe, ja,
dann können wir am Ende das Ziel einmal als Seil erreichen,
weil wir das schleifen können.
Aber wenn wir kein Wasser haben, dann geht es nicht.
Okay, Goal, einmal ist Heil. Loch mit Strohverstopfen habe,
einmal, einmal hat ein Loch und so weiter,
Stroh abpacken, habe Axt,
Axt ist Schaf,
Das andere Beispiel, wo wir das hinkriegen können,
uns mal anschauen können, ist Monkey and Bernanna.
Das ist auch ein ganz berühmtes Problem. Also diese berühmten Probleme sind
immer alle ziemlich konstruiert, aber zeigen trotzdem die Technik.
Folgendes. Äffchen hier hat Hunger, möchte eine Banane.
Und das ist aber so klein, dass es da oben nicht hinreichen kann.
Außerdem, aus irgendeinem dämlichen Gründen hat es in der Hand einen Ball.
Und dann steht hier noch ein Stuhl und man könnte
die Bananen erreichen und mal den Stuhl von da,
wo er steht, direkt unter die Bananen bringt,
darauf klettert,
aber man kann nur klettern
Ball vorher beiseite legt, ja. Und dann können wir
die Bananen erreichen. Also, von Amarell 68 beschrieben,
hungriger Affe steht bei der Tür eines Raumes, Bananen hängen in der Mitte,
dass der Affe sie gerade nicht erreichen kann, ziemlich gemein.
Stuhl steht bei der Tür, ist aber leicht genug,
dass der auf jeden Fall schieben kann.
Affe hält Ball in der Hand,
kann aber nicht mehr als einen Gegenstand zur Zeit halten.
Warum eigentlich ja zwei Hände? Naja. Und dann können wir da
diese Banane-Offs zu schreiben, ja, klein von Share.
Da müssen wir eben als Vorbedingung,
der Stuhl muss in der Mitte vom Raum sein,
Und um dahin zu kommen,
müssen wir hochklettern und at Middle of Room und Floor und so weiter.
Wir haben eine Operation, wenn ein Stuhl verschieben können,
dann steht er an der anschließend nicht mehr bei der Tür und so weiter.
Wir können die Bananen ergreifen und in deiner Vorbedingung ist eben,
dass er empty händet ist.
Also muss er einen Ball wegwerfen. Und wenn man das ausführt,
wunderbar passiert, Climb on Chair, Drop, Walk,
du hast Banana, es it Bananas.
Für einen Irrtgarten wird es ein bisschen schwieriger. Beim Irrgarten
ist eigentlich das Problem, Dass wir das nicht mehr alles zu Fuß aufschreiben wollen.
Ich möchte eigentlich mit einer Datenstruktur für ein Labyrinth beginnen und dann
automatisch die Operatoren erzeugen, die uns den Weg dadurch zeigen.
Okay. Also als ist dieses alles klassische Beispiele für Labyrinthe.
Also in der Anfangszeit waren Labyrinthe eigentlich mehr eine Art auf geringem Raum,
viel Spazierwege unterzubringen, aber die waren so,
dass man sie nicht verlaufen konnte.
Gab da einen Weg dadurch. Die hatten mehr ornamentalen Charakter,
sollten gut aussehen und man konnte sich da eigentlich nicht verlaufen
Erst später wurden sie zur Irrgate im Garten, indem man sich verlaufen kann.
Gut, wir repräsentieren so ein Labyrinth als Raster von Verbundenen,
numberierten Orten und beschreiben die Verbindung durch Nachbarschaftsrelationen.
Und dann haben wir nur eine Art von Operation,
gehe von X nach Y. Und das gilt nur für direkt verbundene Felder.
Und wenn wir jetzt die möglichen Zustände unserer Suche sagen uns,
bei welchem Feld X oder Y wir gerade sind.
Und die Adlist eines Operators, die sorgt dafür,
dass wir jetzt an einem anderen Ort sind und nicht mehr
da,
wo wir vorher waren
Okay, also wir würden hier jetzt sagen,
wie die ganzen Verschiebungen, wie die möglichen Verbindungen sind.
Ja, ich kann von 1 nach 2 kommen,
von 2 nach 3, von 3 nach 4 und so weiter.
Und dann versuche ich automatisch diese Operatoren zu erzeugen.
Und dann würde der Operator, der muss also beim Ad sagen,
wo man jetzt ist und da,
wo man nicht mehr ist und dann haben wir es.
Und wenn wir das jetzt mal ausführen,
dann kriegen wir auch tatsächlich hier für so etwas tatsächlich
eine lange Liste, wie wir laufen müssen,
um das Ziel zu erreichen
Die Bug einbauen, ja. Okay. Dann haben wir
als weiteres Beispiel Szenario auch noch die Klötzchenwelt, die,
das ist so, war irgendwie eine der ersten Aufgaben,
an denen man Robotik mit Planen getestet hat.
Ja, wir stellen uns vor,
dass wir einen Roboter haben, der Kommandos versteht,
die ihm sagen, nimm mal einen Block,
setze ihn auf einen anderen Block,
anbaue uns etwas und diese Kindergartenwelt war so
eins der ersten Ziele gewesen
Also wir haben auf einem Tisch eine Reihe von Baufklötzen.
Die sollen es in einer neuen Konfiguration verbunden werden.
Turm, Brücke und so weiter. Klotz sollte nur bewegt
werden, wenn auf ihm kein anderer drauf ist.
Sonst kann er runterfallen. Und man darf sie nur auf
einen freien Platz legen, wo nicht schon ein anderer Klotz liegt.
So, unsere Blöcke heißen alle ABC oder roter Block.
Orte werden durch das Objekt angegeben, auf dem der Block hut,
ja, auf B, auf dem Tisch.
Und auf jeder Oberfläche soll nur ein einziger anderer Klotz
liegen können,
Denn in dieser Domäne können wir als Aktion sowas haben wie Move-Up.
Make and operator to move, Block A from B2C. Ja,
das ist der Block A und der wird von Weihnachtsziel bewegt.
Und das schreiben wir hier so schön mit Quasi-Quote und erzeugen damit unsere Operatoren.
Und wenn wir jetzt jemand die Aufgabe geben,
baue mir etwas, wo Klotz A auf Platz C liegt,
dann muss er eben dafür sorgen, dass die Blocke,
die bewegt werden sollen,
dass die anderen Ruben runtergenommen werden und so weiter und so
eine Sequenz finden
Wir können Blöcke relativ zu anderen bewegen. Und wir können vom Tisch,
auf den Tisch bewegen. So die Menge der Operatoren,
die wir kriegen, die wir vorsehen müssen,
ist eine Menge der Funktion von der Menge der Klötze,
die überhaupt existieren.
Und dummerweise sind schon bei nur wenigen Blöcken,
die wir haben, sehr, sehr viele Operatoren möglich.
Und deshalb, wenn sie sich von Hand definiert,
sondern wir müssen systematisch erzeugen. Also wenn wir sagen,
wir haben die Blöcke, einfach eine Liste von 30 Blöcken,
dann werden uns die Operatoren hier automatisch erzeugt.
Wir machen es hier mit Amp
Jedes mit jedem kombiniert und fertig.
Gut. Ein typischer GPS-2 Beispiellauf für diese Blöcke wäre,
Vorbedingung A ist auf dem Tisch, B ist auf dem Tisch,
auf Block A ist Platz, auf Block B ist Platz,
ist Platz auf dem Tisch.
Ja, und unser Ziel soll sein,
dass A auf B steht und B auf dem Tisch.
Ja, also das haben wir vorher.
Und das ist das Ziel. Wenn wir das so sagen,
dann kriegen wir ein ziemlich simples Executing.
Bewege, Block A vom Tisch, auf Platz
B. Das ist einfach
Und Block auf den Tisch legen,
auch wieder ziemlich endloses Geplänkel liefern, Vorbedingungen,
A auf dem Tisch, B ist auf A,
auf B ist Platz und auf dem Tisch ist Platz,
können wir A und Hebel wünschen und B auf dem Tabel, ja,
mit den Operatoren erzeugen und dann wird der B von A auf dem Tisch legen.
Also die Sachen sind simpel, was überraschende ist,
obwohl das Szenario so simpel ist, dass die simpelsten Aufgaben oft keine Lösung finden.
Und da war, muss ich sagen, zu dem Zeitpunkt
die KI-Gemeinde ziemlich geknickt. Also wenn wir hier dieses Ziel hatten,
roter Block soll auf dem blauen Block stehen, blauer Block auf grün,
grüner Block auf dem Tisch, auf dem Tisch,
auf dem roten Block soll es frei sein und auf dem Tisch soll es frei sein.
Also das haben wir hier beschrieben, einen Turm,
wo unten der grüne Block ist,
dann der blaue und dann der rote.
Ja, ein simpler Turm aus drei Steinen soll gebaut werden.
Und das bei dieser Darstellung kommt raus,
dass das Problem gar keine Lösung hat
Das kann jedes Kind im Kindergarten, der sagt ihm,
der sind drei farbige Steine,
die stehen so und jetzt stapelt sie mal um,
dass wir am Ende den richtigen Turm haben.
In dieser Welt ist diese Keilerei verteilt der Ziele,
konkurrierender Ziele ist, klappert Sippling problem,
das ist da inherent drin und wir werden es nicht los.
Es müssen mehrere Ziele gleichzeitig erreicht werden und so wie GPS geschrieben wurde,
selbst in Variante 2 gab es in dieser Welt
keine Chance,
dass man die Lösung findet
In der Suche war die Lösung nicht da, weil eben
immer direkt gesucht wurde und es gleich direkt ausgeführt wurde.
Man hat entdeckt, dass wenn man die Vorbedingungen sortiert,
dass es dann in bestimmten Dingungen Lösungen gab,
aber letztendlich ließ sich mit CPS und diesem Forward-Chaining es einfach nicht erreichen,
dass man die Lösung findet.
Die richtige Suchstrategie in der Klötzchenwelt konnte nicht gefunden worden.
In Prolog ist es ein Selbstgänger, da machen wir die Inferenzen
in die Gegenrichtung. Wir suchen nicht So wie GPS,
wir haben hier, gucken wir uns das, die Vorbedingungen,
an die wir erreichen wollen und versuchen, da hinzukommen,
sondern wir machen es in das Riesending im Prolog, geht genau umgekehrt.
Und da hätten wir das Problem nicht. Mit dem vielen Vorsortieren und so,
ist es dann gelungen, dieses Hassmann-Anamoli zu lösen und für
Teile deinen Blogs Volt es tatsächlich hinzukriegen, dieses Umstapeln hinzukriegen, ja?
Also was letztendlich in der Blogs World möglich war,
mit vielen, vielen Versuchen, ist,
dass man natürlich sprachlich seinem Roboter sagen könnt,
Find the block,
which is toler than de van your holding and put it into the box.
Oder die Roboter waren so intelligent, dass man sich schon bemüht,
höflich zu sein. Will you please stack up bost of
the red blocks and eather agreean cube eurer pyramid.
Also was das Brachverstehen lösen konnte, ist,
daraus die Frage zu ermitteln, die Aufgabe zu erschließen.
Ganz ähnlich, wie mit dem Student-Programm.
Und dann tatsächlich die Folge der Operationen zu planen.
Okay, ich will mir eine eigene Zusammenfassung ersparen.
Ich fand, Peter Norwick hat es sehr hübsch gesagt
Er hat aus True McDonalds Article Artificial Intelligence meets natural stupiddity
eine ganz hübsche Passage gefunden. Remember GPS, I know,
GPS, this a colorless term, the noting a particularly
stupid program to solve puzzles. But originally men general problem server,
which cost everybody or lot of needless excitement indestriction.
It should have been court LFGNS, local feature guided network searcher.
Und das ist es eigentlich auch das, was es tut.
Man kann in einem Netzwerk Mit Hilfe von Regeln
suchen und dann Lösungen finden, wenn sie existieren.
Also das ist eigentlich somit die Essenz. Aber ich finde
die folgenden Punkte wichtig. Und das habe ich Ihnen das
auch vorgestellt. Also das Erste, was Sie lernen,
ist bei der Wahl des Namens für ein Programm vorsichtig zu sein.
Nan The Less, GPS-Tersbiene, useful vehicle for exploring programming
a genderal and AI programming in particular. War importantly,
it test been the useful vehicle for exploring the nature of deliberation.
Surely deal emitted Aristotel was a smarter person,
then you are me
Jetzt wird die 8 of the compionite computational model of mind
as a guiding metapher. And the firther 8 of a
verting computer program to help explorer the metapher,
we've been let to a more sorry appreciation of means ends analysis.
At least with in the computer model.
Mastressisted temptation to believe that all thinking follows this model.
Ja, und das ist mit der wichtigsten Satz von allem.
Ich finde, wenn es um die KI-Programmierung geht,
ist es immer ein bisschen im Krieg,
darf man es überhaupt künstliche Intelligenz nennen oder nicht,
nicht inzwischen
Nennen wir das, wo die meiste Arbeit geschieht, Wissensrepräsentation.
Wir sprechen von Inferenz, von Schlussfolgern und tüten uns zu sagen,
dass eine künstliche Intelligenz ist. Einfach, weil der Name
so anspruchsvoll ist. Aber die Methoden, die entwickelt wurden,
die finde ich ungemein wichtig und die haben in vielen,
vielen Fällen die Informatik vorangebracht und wirklich sinnvolle, nützliche Programme geschaffen.
Ich schätze mal, die meisten von Ihnen haben für
irgendwelche Übungsaufgaben und so inzwischen Mathematiker verwendet.
Das Programm hat seine Wurzeln in dem Studentprogramm,
was wir gesehen haben
Sie können, wenn sie in das Buch von Norbik reinschauen,
finden sie im Kapitel nach Student.
Eine schöne Beschreibung für das Maximalsystem gebaut wurde. Und das
Maximalsystem hat die Techniken genutzt, die im Student-Programm drinstecken,
hat die Mathematik dort viel vollständiger formuliert,
sodass wir differenzialgleich in Zekralgleichungen lösen können.
Und daraus letztendlich haben wir inzwischen Programme wie Mathematiker entwickelt,
die mit ganz ähnlichen Techniken eben in der Lage sind,
Gleichungssysteme zu lösen und
die Lösungen grafisch stattzustellen
Und dort, wo wir, selbst auch,
wenn wir selbst integral und Differenzialrechnung gut können,
einfach nicht mehr Lust haben, das selbst zu Ende denken zu müssen.
Wir haben wichtige Werkzeuge, die das für uns tun können. Und das ist eigentlich das,
was man in diesen 60 Jahren, die wir inzwischen setzt,
die KI-Forschung gibt, gelernt haben, Probleme zu analysieren,
festzustellen, was wir an die Lösungswege und uns Werkzeuge zu entwickeln,
wie über die Lösungswege schneller finden können.
Das steckt drin in vielen, vielen Programmen, die eben darauf basieren,
dass wir das beteiligte Wissen formal repräsentieren. Und das,
womit man in vielen Fällen sehr gut weiterkommt, ist,
wenn wir alles Problem wissen, was wir haben,
tatsächlich formal präsentieren, darin suchen und Werkzeuge nutzen,
die uns helfen da drin, Lösungen zu finden.
Ja, geht noch weiter. The appear of AI can be seen,
es ist blood, but we in minds and ends.
The end of a successful AI project can be
a program that are complish as some useful tous,
better faster or cheaper, then it could be then be for.
By that measure, GPS is musli fehler.
Also doesn't solve many problems particular livaal
Höflich gesagt. But the means top that end involved an investigation and
formulization of the problem salving problem process. By debt measure
our reconstruction of GPS is a success to the degree.
In vidual leads the reader to better understanding of the issues.
Das sind bei Forschungsprojekten oft so, dass das,
was man versprochen hat, den Geldgebern, dass das nicht so erreicht wird.
Aber am Ende versteht man, woran es liegt.
Und oder hofft zu verstehen, woran es liegt und wie
man im nächsten Projektantrag das verbessern kann und dann zu besseren Lösungen zu kommen.
Und Was mir in dieser Vorlesung sehr wichtig war,
ist, dass wir ein Programmierstil lernen,
in dem wir nicht nur Daten modellieren, Objekte modellieren,
Klassen modellieren, Strukturen modellieren, sondern wo wir anfangen,
den Problemmlöseprozess zu modellieren, sodass wir auch in der Lage sind,
Programme zu schreiben, bei denen wir den Algorithmus selbst nicht kennen,
sondern Werkzeuge zu entwickeln, die uns helfen,
die Algorithmen zu finden.
Ja, das ist eigentlich das,
was für mich die ganze KI-Welt so faszinierend macht, ist,
indem wir aufschreiben, dass wir wissen, die Regeln aufschreiben,
die zum Lösungsweg führen könnten, den Computer nehmen,
Dass er uns hilft, dieses Geflecht zu analysieren und darin mögliche Lösungen aufzuzeichnen.
Und die Lösung sind eben nicht immer nur numerischer Art,
dass man Maximum beim Minimum einer Optimierungsfunktion sucht,
sondern dass wir über Fakten, Daten, Schlussfolgern,
dass wir Möglichkeiten haben mit sehr hybriden Datenstrukturen umzugehen.
Also wenn Sie sich an die Frühlock-Beispiele erinnern,
die ich Ihnen aufgeschrieben habe, das Wissen über diese Rätsel,
das ging über viele, viele unterschiedliche Arten von Dingen.
Das ist sehr schwer, das zu modellieren in Programmiersprachen,
die mit einem Strong-Typing arbeiten,
weil wir da nicht so schnell und einfach Beziehungen ausdrücken können, beliebiger Art.
Wir müssten, wenn wir Zebras im Zusammenhang mit Farbe eines Hauses bringen will,
wollten Klassen schreiben, die das können, ja.
Und in der Welt, deklarativen Welt, wo wir einfach Fakten aufschreiben können,
ist das ja viel einfacher. Und das war eigentlich das,
was ich gehofft habe, dass Sie an diesen Beispielen,
die wir hier ausgesucht haben, auch sehen können.
Gibt es zu dem Punkt hier Fragen? Gut,
dann werden wir das nächste Mal die Vorlesung damit zum Abschluss bringen,
dass ich die abschließenden Folien durchgehe,
indem wir einen Rundumschlag machen,
was wir in diesem Semester so alles gemacht haben und uns
noch eine Probeklausur anschauen und die letzten Fragen,
wie die Klausur besprechen können.
Danke für die Aufmerksamkeit