← ST-Computer 01 / 1988

Elemente der kĂŒnstlichen Intelligenz (8): Implementierung von Rahmen

Grundlagen

Eine EinfĂŒhrung in Programmiermethoden und Sprachen der KI 8. und letzter Teil

In diesem letzten Teil der Serie ĂŒber kĂŒnstliche Intelligenz, möchte ich Sie mit dem Konzept des Rahmens vertraut machen. Wie ich bereits in einer der ersten Folgen dieser Serie betont habe, erkennt man Intelligenz auch daran, daß aus unvollstĂ€ndigen Informationen richtige SchlĂŒsse gezogen werden, bzw. fĂŒr die jeweilige Situation nĂŒtzliche Aktionen eingeleitet w erden. Gerade aber wenn die Wissensbasis unvollstĂ€ndig ist, bekommt ein Verfahren besondere Bedeutung, das als analoges Schließen bekannt ist.

Analoges Schließen bedeutet ganz einfach, daß das Programm die Kenntnis aus benachbarten Wissensgebieten benutzt um in der konkreten Situation Informationsmangel zu kompensieren. Besonders im Bereich des Lernens ist analoges Schließen von elementarer Bedeutung. Kein Wunder also, wenn die KI-Forscher nach Mechanismen gesucht haben, die analoges Schließen auch dem Computer ermöglichen sollen.

Rahmen dienen der Organisation von Wissen

Um dem Computer AnalogieschlĂŒsse zu ermöglichen, muß das zu vergleichende Wissen in einer geeigneten Form gespeichert werden. Hierzu sind die Rahmen (engl.: frames) besonders geeignet. Ein Rahmen ist nichts anderes als eine vereinheitlichte Property Liste. Und zwar besteht die Propertyliste aus dem Rahmen, Schlitz (engl.: slot) und Merkmalen (engl.: facettes). Hat man nun zwei Rahmen mit Ă€hnlichen Eigenschaften, so können Informationen aus dem einen Rahmen in die entsprechenden Merkmale des anderen Rahmens vererbt werden. Wir wollen diese Eigenschaften von Rahmen am Beispiel des Programmes FRAME.LSP erarbeiten, welches ich in Anlehnung an [-] fĂŒr XLISP geschrieben habe (Listing 1). Eine vollstĂ€ndige Implementation einer Übungssprache (PFL: Paedago-gical Frame Language) ist bei [-] gegeben. Über die Einordnung von Rahmen in den KI-Bereich kann man bei [-] nach-lesen. KĂŒmmern wir uns also zunĂ€chst einmal um die Propertyliste, die alles beherrschende Datenstruktur unseres Programms.

Die Propertyliste

In Lisp gibt es eine Liste, in der man Eigenschaften eines Objektes ablegen kann, eben die Propertyliste. Diese ist nicht zu verwechseln mit Assoziationslisten, die man in beliebiger Anzahl erzeugen (und an Symbole binden) kann. Der Zugriff auf die Propertyliste des (X)Lisp Interpreters erfolgt ĂŒber die Funktionen SETF und GET. Die Syntax dieser beiden Funktionen lautet:

(getXsym Xeig ) Holt den Wert der Eigenschaft eig des Symbols sym von der Propertyliste.

Das Symbol. Die Eigenschaft des Symbols, welche einen Wert hat.

(setf )

Diese Funktion gibt den Wert wert an die in der Zugriffsform zugr enthaltene Eigenschaft eig des Symbols sym der Propertyliste.


Die Zugriffsform. Sie muß, wenn evaluiert, den Wert der Eigenschaft des Symbols auf der Propertyliste erzeugen. In unserem Fall also (get <eig»


Der Wert, den die in der Zugriffsform enthaltene Eigen schalt eig des Symbols sym auf der Propertyliste erhalten soll.

An einem Beispiel wird der Sachverhalt leicht klar. Das Symbol KLOTZ mit der Eigenschaft FARBE soll den Wert ROT erhalten:

(setf (get ’klotz ’farbe) ’rot)

Dies ist die Zugriffsform. Sie reproduziert spÀter wieder den Wert der Eigenschaft FARBE des Symbols KLOTZ aus der Propertyliste.

Anschließend kann mit der Zugriffsform der Wert wieder aus der Propertyliste geholt werden:

(get ’klotz ’farbe)
ROT1
In XLISP gibt es noch zwei spezielle Zugriffsfunktionen fĂŒr die Propertyliste: REMPROP und PUTPROP. Die erste entfernt eine Eigenschaft aus der Propertyliste eines Symbols, die zweite ist Ă€quivalent zur Funktion SETF. Wir benutzen aus KompatibilitĂ€tsgrĂŒnden aber die Funktion SETF.

Wie wir bereits gelesen haben, ist ein Rahmen nichts anderes als eine normierte Propertyliste mit den Elementen RAHMEN, SCHLITZ, MERKMAL Abb. 1 zeigt den Aufbau eines Rahmens in der Propertyliste. NatĂŒrlich ist die Anzahl der Rahmen in der Propertyliste, bzw. die Anzahl der Schlitze im Rahmen oder die Anzahl der Merkmale eines Schlitzes nur durch den verfĂŒgbaren Speicherplatz des Computers beschrĂ€nkt.

Nehmen wir einmal an, wir wollten unser Wissen ĂŒber Computer in Rahmen fassen. Dann könnte der Rahmen fĂŒr den ATARI ST Computer vielleicht so aussehen, wie Abb. 2 es zeigt. Der Name des Rahmens ist ATARI, der erste Schlitz in diesem Rahmen ist die Typenbezeichnung MODELL mit dem Merkmal WERT 1040ST. Der zweite Schlitz des gleichen Rahmens ist SPEICHER. StandardmĂ€ĂŸig wird er 1040ST mit 1Mb Speicher ausgeliefert. Der Besitzer obigen GerĂ€tes hat aber sein GerĂ€t auf 2Mb aufgerĂŒstet. Dies ist erkennbar an den beiden Merkmalen STANDARD 1MB und WERT 2MB. Auch fĂŒr den Schlitz MONITOR sind zwei Merkmale vorhanden STANDARD SW und WERT COLOR, woraus zu entnehmen ist, daß dieser Computer entgegen dem Standard mit einem Colormonitor ausgerĂŒstet ist. Nun bleibt nur noch die Frage, wie man solch einen Rahmen einrichtet, bzw. die Informationen aus dem Rahmen abruft und weiterverarbeitet? Und wie funktioniert analoges Schließen mit den Rahmen?

Informationen holen

Es ist am leichtesten, aus der Propertyliste Informationen eines bestehenden Rahmens zu holen. Deshalb zunĂ€chst also die Zugriffsoperationen. Nehmen wir an, daß die Propertyliste den Rahmen aus Abb.2 enthĂ€lt. Wir erhalten den kompletten Rahmen, wenn wir den Befehl (get ’atari 'rahmen) eingeben. Man erhĂ€lt dann das Resultat aus Abb.3.

Wollen wir nicht den ganzen Rahmen, sondern nur ein Merkmal eines bestimmten Schlitzes eines bestimmten Rahmens, dann mĂŒssen wir uns eben durch die gegebene Rahmenliste Vorarbeiten. Inzwischen sind wir ja schon zu geĂŒbten XLisp(l)ern geworden, sodaß wir ohne MĂŒhe in der obigen Liste eine sogenannte Assoziationsliste erken nen [(-)]. Der car dieser Liste ist der SchlĂŒssel, der cadr ist der zugehörige Wert. Diesen erhalten wir mit der Funktion assoc. Abb. 3 zeigt einige Zugriffe auf Elemente des Rahmens mit Hilfe der Funktion assoc.

Die assoc-wurschtelei lĂ€ĂŸt sich natĂŒrlich durch Definition ei ner Funktion umgehen, die den Namen des Rahmens, Schlitzes und Merkmals als Parameter ĂŒbernimmt und die Li ste mit dem Merkmalswert zurĂŒckgibt. Diese Funktion erhĂ€lt den sinnvollen Namen rhol und findet sich zu Beginn des Listingl. Die Funktion rhol-rahmen gibt den ganzen Rahmen zurĂŒck. Falls der gewĂŒnschte Rahmen allerdings nicht vorhanden ist, wird er mit Hilfe der setf Funktion neu erzeugt.

Das Erzeugen eines Rahmens in der Propertyliste

Diese Funktion ist erheblich komplizierter zu realisieren und bedarf daher einiger Vor arbeit. ZunĂ€chst einmal muß getestet werden, ob der Rahmen exisitert. Wenn dies nicht der Fall ist, wird der Rahmen mit der obigen Funktion 2 rhol-rahmen erzeugt. Andernfalls wird der Rahmen mit der selben Funktion als Assoziationsliste geholt und auf das Vorliegen eines entsprechen den Merkmals getestet. Es ver steht sich, daß derselbe Wert nicht zweimal abgespeichert wird. Liegt der Wert des Merkmals also bereits vor, dann wird nicht noch einmal gespeichert, sondern einfach NIL zurĂŒckgegeben. Besondere Beachtung sollte hierbei die Art und Weise der Erweiterung finden, wenn ein Schlitz, bzw. ein Merkmal noch nicht vorliegen. Abb. 4 zeigt die Vorgehensweise, die wir uns nun etwas nĂ€her unter die Lupe nehmen. Zu Beginn soll z.B. der Rahmen (ATARI (MODELL (WERT 1040ST))) auf der Propertyliste vorliegen und es soll der Schlitz SPEICHER mit dem Merkmal (WERT 2MB) hinzugefĂŒgt werden. Dazu rufen wir die Funktion (rpack ’atari 'Speicher 'wert ’2mb) auf. Der interessanteste Teil der Funktion lĂ€uft bereits bei der Initialisierung mit dem LET-Konstrukt ab. Hier wird wertliste als gebundene Variable erzeugt, mit einem Wert, der sich durch Aufruf der Funktion (folge-pfad '(Speicher wert) ’(atari (modell (wert 1040st)))) ergibt (siehe Listing 1). Diese Funktion testet, ob die Liste mit dem Pfad (d.h. '(Speicher wert)) bereits leer ist. Dann wird die Argumentliste liste zurĂŒckgegeben. Sonst ruft sich die Funktion selbst auf, allerdings mit dem Rest des Pfades und dem Ergebnis der Funktion (erweitern 'Speicher '(atari (modell (wert 1040st))). In dieser Funktion erfolgt dann der eigentliche Teil der Erweiterung des Rahmens. Die erste Klausel der Disjunktion trifft zu, wenn der SchlĂŒssel (SPEICHER) bereits in der Assoziationsliste des Rahmens enthalten ist. Dann braucht natĂŒrlich nicht erweitert zu werden, und die Funktion gibt die Assoziationsliste mit dem SchlĂŒssel und dem Wert zurĂŒck, um dann im nach sten Schritt von folge-pfad als Ergebnis zurĂŒckgegeben zu werden. Falls nun aber wie in unserem Beispiel der SchlĂŒssel SPEICHER noch nicht in der Assoziationsliste des Rahmens enthalten ist, tritt die zweite Klausel der Disjunktion in der Funktion erweitern in Kraft. Diese ersetzt den CDR des letzten Listenknotens durch die Liste die die Liste des SchlĂŒssels ersetzt (mittlerer Teil der Abb. 4). Damit wurde an die Liste etwas angefĂŒgt, die ursprĂŒngliche Liste also verĂ€ndert. An diesem Beispiel sollte klar geworden sein, daß LISP Knoten nichts anderes als Knoten eines binĂ€ren Baumes sind, deren erster Teil ein Zeiger auf ein Datenelement ist und dessen zweiter Teil ein Zeiger auf den nĂ€chsten LISP Knoten. Als Funktionswert wird dann die Liste mit dem SchlĂŒssel (d. h. dem Schlitz SPEICHER) zurĂŒckgegeben. Diese wird dann beim RĂŒcksprung aus der tieferen Rekursionstufe an die lokal gebundene wert-liste ĂŒbergeben. FĂŒr AnfĂ€nger verblĂŒffend ist dabei wahrscheinlich, daß trotz Verwendung einer lokal gebundenen Variablen (der Liste wert-liste) ein globaler Effekt erzielt wird. Der untere Teil der Abb.4 illustriert diesen Effekt. In der Funktion 2 rpack wird nĂ€mlich (wenn der Wert 2MB nicht in der Wertliste ist, wie bei uns der Fall!) der CDR des letzten Elementes der Werteliste durch die Liste mit dem Wert 2MB ersetzt. Da aber der CAR des LISP-Knotens von 2 wert liste auf einen global gebundenen LISP-Knoten zeigt, wird beim AnfĂŒgen eines Elementes an die Liste von wert-liste gleichzeitig ein globaler Effekt erreicht und der CDR des letzten Elementes des Rahmens hinzugefĂŒgt.

DĂ€monen als stille Helfer

Jeder Programmierer kennt die Situation: Man fragt einen Da tensatz ab und stellt fest, daß die abgefragte Information nicht vorhanden ist. Da wĂŒnscht man sich schon manchmal ein paar DĂ€monen, die ohne viel Aufsehen die passenden Werte besorgen, damit die anfragende Routine nicht abstĂŒrzt oder falsche Ergebnisse produziert. Solche DĂ€monen aber kann man in einem Rahmen leicht implementieren. Schauen wir uns zu diesem Zweck einmal die Datenbank ĂŒber Automobile in Listing 1 an. Dort sehen wir, daß die Informatioen ĂŒber die verschiedenen Autotypen nicht bei allen Typen vollstĂ€ndig sind. Über VW weiß die Daten bank z.B. nur, daß der meistgekauft Typ der GOLF ist, weshalb er als Standard eingesetzt wur de. Die Anfrage (rhol ’vw 'typ 'wert) wĂŒrde also NIL ergeben, da das gesuchte Merkmal im Schlitz typ nicht vorhanden ist. Dagegen liefert die Anfrage 2 (rhol-w-s ’vw typ) er wartungsgemĂ€ĂŸ (GOLF), da nach mißlungener Abfrage nach dem Wert, die Abfrage nach dem Merkmal Standard im gleichen Schlitz erfolgt. Ein DĂ€mon kann aber noch mehr. Wenn wir das Alter eines Autos nicht kennen, dann könnten wir einen WENN-NOETIG DĂ€ mon aktivieren, der ein springt, wenn weder ein Stan dard noch ein Wert vorliegen. Nehmen wir einmal an, wir wollten fĂŒr eine Gebrauchtwagendatenbank den Vorbesitzer eines Wagens in den Rahmen mit aufnehmen. Dazu verpassen wir z.B. dem Rahmen OPEL den WENN-NOETIG DĂ€mon Frage fĂŒr den Schlitz Vorbesitzer:

(rpack ’opel ’vorbesitzer ’wenn-noetig Trage)
(FRAGE)
Fragen wir nun nach dem Vorbesitzer des Opel:
(rhol-w-s-d ’opel ’vorbesitzer)

Da weder ein Wert fĂŒr den Vorbesitzerschlitz, noch ein Standard bekannt ist, wird der DĂ€mon aktiv (wir haben rhol-w-s-d aufgerufen!) und lĂ€ĂŸt die Funktion Frage ablaufen, die eine Eingabe fĂŒr den Wert verlangt und diesen im Schlitz abspeichert. Abb. 5 zeigt das Protokoll der Abfrage.

Noch eindrucksvoller ist allerdings die Vererbung von Eigenschaften. Um einen DĂ€mon zu implementieren mĂŒĂŸten wir nun alle Automobile mit dem entsprechenden wenn-noetig DĂ€mon versehen. Viel einfacher wĂ€re es, könnte man fĂŒr alle Autos gleichzeitig einen entsprechenden DĂ€mon vereinbaren. Das ist möglich, wenn man einen Schlitz Ist vereinbart, der die Art des Rah mens definiert. Also z.B. (rpack ’lancia ’ist 'wert ’auto). Weiterhin fĂŒhren wir umgekehrt einen Rahmen Auto, der ebenfalls einen Schlitz Ist enthĂ€lt und in dem als Merkmal Wert alle Autos der Datenbank aufgefĂŒhrt sind (siehe Li sting 1). Die Funktionen rhol-i, rhol-n und rhol-z holen sich ĂŒber den Schlitz Ist Informationen der verwandten Rahmen und vererben diese Informationen weiter. Die vererbten Informationen können Werte aber auch DĂ€monen sein. Abb. 6 zeigt die Abfrage unter Benutzung der Vererbung.

Vererbung von Informationen

Die drei Funktionen rhol-i, rhol-n und rhol-z ĂŒbernehmen die Vererbung von Informationen. Alle Vererbung geschieht dabei ĂŒber den 2 Ist Schlitz. Schauen wir uns dazu einmal Abb.6 genauer an. Die erste Abfrage lautet (rhol-w-s-d ’vw ’alter). Da kein Schlitz ALTER in der Assoziationsliste des Rahmens enthalten ist, liefert weder die Frage nach dem Merkmal WERT, noch die Frage nach dem Merkmal STANDARD noch die Anfrage nach dem Merkmal WENN-NOETIG (DĂ€mon) einen Wert.

Die nĂ€chste Anfrage ist (rhol-i ’vw ’alter). Diesmal wird die Informationsvererbung ĂŒber den Ist-Schlitz des Rahmens verwendet. Dazu werden mit Hilfe der Funktion rhol-klas-sen alle durch den Ist1-Schlitz miteinander verbundenen Rahmen aufgefunden. Die Hilfsfunktion 2 rhol-il schaut nun in jedem Rahmen der Liste Klassen nach, ob der gefragte Schlitz (in unserem Beispiel ALTER) mit dem Merkmal WERT vorhanden ist. Wenn ein Rahmen mit diesem Merkmal gefunden wurde, wird der Merkmalswert zurĂŒckgegeben. Aus diesem Grunde ist die Antwort in Abb. 6 auch (1), da im Rahmen LANCIA im Schlitz ALTER im Merkmal WERT der Wert 1 gefunden wurde.

Das Ergebnis der Abfrage (rhol-n ’vw ’alter) ist das glei che, weil in der ersten Klausel der Hilfsfunktion rhol-nl ebenfalls alle Elemente der Liste Klassen auf das Vorliegen des Merkmals WERT getestet werden.

Anders reagiert das Programm lediglich auf die Anfrage (rhol-z ’vw ’alter). Nunmehr werden nĂ€mlich alle Elemente der Liste Klassen zunĂ€chst auf das Vorliegen der Merkmale WERT, STANDARD und WENN-NOETIG (DĂ€mon) untersucht, bevor das nĂ€chste Element der Klassen untersucht wird. Und als DĂ€mon findet rhol-z in der Assoziationsliste des Rahmens AUTO (steht an erster Stelle der Liste Klassen) das Merkmal WENN-NOETIG mit dem Merkmal FRAGE. Der DĂ€mon WENN-NOETIG wird also aktiv und fragt nach dem Alter. Abb. 7 zeigt die Art der Vererbung, wie sie durch rhol-i, rhol-n1 und rhol-z verwendet wird. Man erkennt, daß die Buchstaben mnemonische Bedeutung haben. Die Reihenfolge der Abarbeitung ist allerdings willkĂŒrlich gewĂ€hlt (Wo bliebe sonst die mnemonische Wirkung?).

XLISP’s Geisterstunde (DĂ€monenaktivierung)

Wie aktiviert man nun einen DĂ€mon? Das ist in der Tat ein ParadestĂŒck fĂŒr die LeistungsfĂ€higkeit von LISP. Schließlich muß der Interpreter nun je nach DĂ€mon ein anderes LISP Programm aktivieren, daß irgendwo als Liste vorliegt. Den Code fĂŒr die DĂ€monenaktivierung finden wir in den Funktionen rhol-w-s-d und 2 rhol-n2. In beiden findet man die Funktion mapcan als Motor der Aktivierung. Die Funktion mapcan hat folgende Syntax:

(mapcan [...])
Es bedeuten:
: Eine gĂŒltige LISP Funktionsdefinition.
<liste?>: FĂŒr jedes Argument der Funktion eine Liste mit Argumentwerten.

Die Funktion wendet nun auf jedes Element der Listen an. Die zurĂŒck gegebenen Werte werden zu einer Liste zusammengefaßt. Leider ist mapcan in der XLISP Dokumentation nicht beschrieben, funktioniert aber trotzdem. Die obige Definition stimmt mit der Definition von mapcar in der XLISP Dokumentation ĂŒberein. Trotzdem arbeiten beide Funktionen leicht unterschiedlich. WĂ€hrend mapcar die Ergebnisse in eine Liste packt, zieht mapcan die Ergebnisse in einer Liste mittels nconc zusammen. Das setzt natĂŒrlich voraus, daß das Ergebnis der Funktion eine Liste ergibt, da sonst nicht zusammengezogen werden kann.

Beispiel:
(mapcar ’equal ’ (12 3) ’ (2 2 2)) (NIL TNIL)

(mapcar '(lambda (a b) (list (equal a b))) ’(1 2 3) ’(2 2 2)) ((NIL) (T) (NIL))

(mapcan '(lambda (a b) (list (equalab))) ’(1 2 3) ’(2 2 2)) (NIL T NIL)

Mapcar und mapcan erlau ben also die Anwendung der gleichen Funktion auf mehrere Parameter hintereinander. Im Falle unserer DĂ€monen, holt sich die Funktion rhoi-w-s-d also zunĂ€chst mit (rhol rahmen schlitz ’wenn-noetig) Liste aller als DĂ€mon agierender Funktionsnamen und wen det dann die Schablone im mapcan Aufruf sukzessiv an.

Vererbung in AnalogieschlĂŒssen

Wie Eingangs erwĂ€hnt, ist analoges Schließen ein typisches Merkmal von Intelligenz. Aus 2 stammt das folgende Beispiel. Wenn Jemand sagt, Fred ist wie ein BĂ€r, dann ĂŒbertrĂ€gt der Zuhörer Eigenschaften des BĂ€rs auf den ihm unbekannten Fred. Ein Anlogieschluß ist also nichts anderes als das Übertragen (Vererben) von Informationen. Und da wir im letzten Abschnitt mehrere Methoden zur Informationsvererbung kennengelernt haben, soll das oben genannte Beispiel in unserer Rahmensprache nachvollzogen werden. Im letzten Teil des Listing 1 finden Sie die Rahmen fĂŒr Fred und Ted. Abb. zeigt, wie die GrĂ¶ĂŸe und Gang art von Fred aus der Analogie zu Ted vererbt wird.

Schlußwort

Diese Serie ist am Ende angelangt. Es gĂ€be natĂŒrlich noch vieles zu berichten, vor allem, weil der Fortschritt im Bereich der Informatik so ungeheuer schnell voranschreitet. So habe ich beispielsweise gerade vor ein paar Monaten von den ersten Neuronenchips erfahren, die in den USA verkauft werden. Parallel verarbeitende Rechnerarchitekturen werden in Zukunft sicherlich eine bedeutende Rolle spielen. Kurz und gut, wir stehen vor der Schwelle vieler neuer Verfahren und Methoden und vieles (wenn auch sicher nicht alles) was heute kaum vorstellbar ist, wird sich mit neuen, von der herkömmlichen v. Neumann Architektur abweichenden Konzepten erreichen lassen.

Ich bedanke mich bei Ihnen, lieber Leser, daß Sie mir bis hierher gefolgt sind. Als kleines Dankeschön fĂŒge ich der PL) demnĂ€chst eine Shell fĂŒr XLISP und TOY-Prolog bei, so daß der Benutzer sehr bequem einen Entwicklungszyklus mit Hilfe eines Editors aus der PD durchfĂŒhren kann.

Literatur

[1] Finin.T.ImplementingPFL.Part 1 & 2. AI Expert, Novembers De-cember 1986. CL Publications, Palo Alto, CA.

[2] Lenat, D.B. Software fĂŒr kĂŒnstliche Intelligenz. Spektrum der Wissenschaft. Sonderheft Computersoftware 1985.

[3] Samow, K. Elemente der kĂŒnstlichen Intelligenz. 1. Teil: Atome und Listen, ST-Computer, 3/ 87, p.37ff.

[4] Winston, P.H. & B.K.P. Horn. I.ISP. 2nd Edition. Addison Wesley Publishing Company. Reading, Massachusetts. 1984.

Dies war der letzte Teil der Serie 'KĂŒnstliche Intelligenz’. Falls Sie Interesse an dem Thema KI haben, dann schreiben Sie uns was Sie aus dem Bereich der KI interessieren wĂŒrde. Wir versuchen darauf einzugehen und je nach Nachfrage weitere, auch praxisbezogene Artikel zu veröffentlichen. NatĂŒrlich sind auch Sie aufgefordert, eigene BeitrĂ€ge zu liefern. Zu Schriften bitte direkt an:

MERLIN-Computer GmbH
KI Industriestr. 26
6236 Eschborn Listings

Rahmenimplementation nach Winston und Horn

;Rahmenimplementation nach Winston und Horn: LISP. Second Edition 1984. ;*********************************** (defun rhol (rahmen schlitz merkmal) (cdr (assoc merkmal (cdr (assoc schlitz (cdr (get rahmen 'rahmen))))))) ;Holt den Wert eines Rahmens aus einem Schlitz mit einem bestimmten Merkmal ;*********************************** (defun rhol-rahmen (rahmen) (cond ((get rahmen 'rahmen)) (t (setf (get rahmen 'rahmen) (list rahmen))))) ;Holt die ganze Assoziationsliste eines Rahmens uon der Propertyliste ;*********************************** (defun erweitern (schluessel liste) (or (assoc schluessel (cdr liste)) (cadr (rplacd (last liste) (list (list schluessel)))))) ;Erweitert die Assotiationsliste des Rahmens um einen SchlĂŒssel, ;wenn er noch nicht in ider Assoziationsliste vorhanden ist. ;*********************************** (defun folge-pfad (pfad liste) (cond ((null pfad) liste) (t (folge-pfad (cdr pfad) (erweitern (car pfad) liste))))) ;Gibt die Liste mit dem Schlitz und Merkmal zurĂŒck, falls es ;schon in der lAssoziationsliste des Rahmens existiert. Sonst ;nur die Liste mit dem neu leingetragenen SchlĂŒssel. ;*********************************** (defun rpack (rahmen schlitz merkmal wert) (let ((wert-liste (folge-pfad (list schlitz merkmal) (rhol-rahmen rahmen)))) (cond ((member wert wert-liste) nil) (t (rplacd (last wert-liste) (list wert)) wert)))) ;Erzeugt einen neuen Rahmen, Schlitz oder Merkmalswert, falls ;noch nicht auf der Propertyliste vorhanden. (defun rweg (rahmen schlitz merkmal wert) (let ((wert-liste (folge-pfad (list schlitz merkmal) (rhol-rahmen rahmen)))) (cond ((member wert wert-liste) (delete wert wert-liste) t) (t nil)))) ;vernichtet einen Rahmen. ;*********************************** (defun rcheck (rahmen schlitz merkmal wert) (cond ((member wert (rhol rahmen schlitz merkmal)) t) (t nil))) ;Checkt eine Rahmen-Schlitz-Merkmal-Wert-Kombination auf Existenz. ;*********************************** (defun rklammer (rahmen1 rahmen2 schlitz) (rplacd (rhol-rahmen rahmen1) (list (folge-pfad (list schlitz) (rhol-rahmen rahmen2)))) schlitz) ;Klammert zwei Rahmen bei einem bestimmten Schlitz zusammen ;(Zwei Rahmen erben gleiche Merkmale), ;*********************************** (defun rhol-klassen (start) (reverse (rhol-klassenl (list Start)nil))) (defun rhol-klassen1 (liste klassen) (cond ((null liste) klassen) ((member (car liste) klassen) (rhol-klassen1 (cdr liste) klassen)) (t (rhol-klassen1 (append (rhol (car liste) 'ist 'wert) (cdr liste)) (cons (car liste) klassen))))) ;Die beiden Funktionen liefern eine Liste aller durch den Schlitz ;"IST" imiteinander verbundnen Rahmen. ;*********************************** (defun rhol-z (rahmen schlitz) (rhol-zl schlitz (rhol-klassen rahmen))) (defun rhol-zl (schlitz klassen) (cond ((null klassen) nil) ((rhol-w-s-d (car klassen) schlitz)) (t (rhol-zl schlitz (cdr klassen))))) ;Gibt den Wert eines Rahmen-Schlitzes zurĂŒck, ;indem zunĂ€chst das Merkmal "WERT" gesucht wird. Fehlt dieses, ;wird das Merkmal "STANDARD" gesucht. Fehlt auch dieses, ;wird das Merkmal "WENN-NOETIG" nach DĂ€monen abgesucht. ;*********************************** (defun rhol-n (rahmen schlitz) (let ((klassen (rhol-klassen rahmen))) (cond ((rhol-nl schlitz klassen 'wert)) ((rhol-nl schlitz klassen 'Standard)) ((rhol-n2 schlitz klassen 'wenn-noetig)) (t nil)))) (defun rhol-n1 (schlitz klassen schluessel) (cond ((null klassen) nil) ((rhol (car klassen) schlitz schluessel)) (t (rhol-n1 schlitz (cdr klassen) schluessel)))) (defun rhol-n2 (schlitz klassen schluessel) (cond ((null klassen) nil) ((mapcan (lambda (demon) (funcall demon (car klassen) schlitz)) (rhol (car klassen) schlitz schluessel))) (t (rhol-n2 schlitz (cdr klassen) schluessel)))) ;Wie rhol-z, allerdings werden sĂ€mtliche Elemente der Liste Klassen ;zuerst auf Werte, Standard und Wenn-noetig Merkmale untersucht. ;*********************************** (defun rhol-i (rahmen schlitz) (rhol-i1 (rhol-klassen rahmen) schlitz)) (defun rhol-i1 (klassen schlitz) (cond ((null klassen) nil) ((rhol (car klassen) schlitz wert)) (t (rhol-i1 (cdr klassen) schlitz)))) ;Wie rhol-z, allerdings schaut diese Funktion nur nach Werten. ;*********************************** (defun rhol-w-s (rahmen schlitz) (cond ((rhol rahmen schlitz 'wert)) ((rhol rahmen schlitz 'Standard)))) ;Hole Wert eines Rahmen-Schlitz-Merkmais. ;Wenn nicht vorhanden schaue ;bei Standard nach. (defun rhol-w-s-d (rahmen schlitz) (cond ((rhol-w-s rahmen schlitz)) (t (mapcan (lambda (demon)(funcal1 demon rahmen schlitz)) (rhol rahmen schlitz 'wenn-noetig))))) ;Wie rhol-w-s, schaut aber zusĂ€tzlich noch nach Wenn-nötig DĂ€monen, ;wenn weder ein Wert noch ein Standard vorliegt. (defun frage (rahmen schlitz) (print '(bitte geben Sie einen wert fuer schlitz < .schlitz > in dem rahmen < .rahmen > ein)) (terpri) (let ((response (read))) (cond (response (rpack rahmen schlitz 'wert response) (list response)) (t nil)))) ;Beispiel eines Wenn-nötig DĂ€monen. ;*********************************** (defun berechne-leistung (rahmen schlitz) (let ((alter (rhol-w-s rahmen 'alter))) (cond (alter (list (rpack rahmen km-leistung wert (# 28800.0 (car alter)))))))) ;Beispiel eines Wenn-noetig-DĂ€monen fĂŒr die Automobildatenbank. ;*********************************** ;Datenbank ĂŒber Automobile ;Wissen ĂŒber Lancias (rpack 'lancia ist 'wert auto) (rpack 'lancia 'typ 'Standard ’thema) (rpack 'lancia km-leistung wert 15000.0) (rpack 'lancia alter 'wert 1) ;Wissen ĂŒber Opel (rpack opel 'ist 'wert auto) (rpack 'opel 'typ 'Standard ’rekord) ;Wissen ĂŒber VW (rpack uw 'ist wert auto) (rpack 'uw 'typ 'Standard 'go1f) ;Wissen ĂŒber Autos allgemein (rpack auto ist 'wert lancia) (rpack 'auto 'ist wert 'opel) (rpack 'auto 'ist 'wert 'vw); (rpack 'auto 'km-leistung 'wenn-noetig 'berechne-leistung) (rpack 'auto alter 'wenn-noetig 'frage) ;Datenbank zum Analogieschluß ;Fred ist wie ein BĂ€r ;Rahmen ĂŒber Fred (rpack 'fred 'ist 'wert 'mann) (rpack 'fred 'wohnung wert "Hauptstr. 15") (rpack 'fred 'groesse wenn-noetig ’wie-baer) (rpack 'fred gangart wenn-noetig 'wie-baer) ;Rahmen ĂŒber Teddy BĂ€r (rpack 'ted 'ist 'wert 'baer) (rpack 'ted wohnung wert 'hoehle) (rpack 'ted groesse wert gross) (rpack ted gangart wert 'polternd) (rpack 'ted ’nahrung 'wert ’honig) (defun wie-baer (rahmen schlitz) (let ((wert (car (rhol 'ted schlitz wert)))) (cond (wert (list (rpack rahm en schlitz 'wert wert)))))) ;Informationen ĂŒber Computer (rpack 'atari modell 'wert '1040st) (rpack 'atari 'Speicher 'Standard '1mb) (rpack 'atari 'Speicher 'wert ’2mb) (rpack atari 'monitor 'wert 'color) (rpack atari 'monitor 'Standard 'sw)