Die letzte der zu besprechenden komplexen Funktionen zur
Listenbearbeitung ist die Funktion
(assoc), die an
sich gar nicht schwierig ist. Man sollte nur das Konzept
der Assoziationsliste verstanden haben: Assoziationslisten
sind Datenbanken mit frei wählbaren Datenfeldern. Ein typischer
Fall für eine kleine Datenbank wäre z.B. ein Informationsdienst
für bereits geschriebene LISP-Routinen. Datenfelder könnten
'Name', 'Datum', 'Zweck', 'Zeilen' und 'Anmerkung' sein.
Die Daten werden mit einem Texteditor in eine Datei geschrieben:
(setq programm-info
'(
(biegen
(name "biegen.lsp")
(datum 1 4 95)
(zweck "Macht Bogen aus Linie")
(zeilen 36)
)
(kleben
(name "kleben")
(datum 1 4 95)
(zweck "Fügt zwei kollineare Linien zusammen")
(zeilen 147)
(anmerk "Scheint nur nachts zu funktionieren!")
)
)
)
Speichern Sie die Textdatei als 'prg-info.lsp' ab und laden
Sie sie dann in AutoCAD mit
(load"prg-info").
Die Datenbank steht Ihnen nun zur Verfügung, auch wenn sie
erstmal nur zwei Einträge hat. Wie können Sie nun darauf zu-
greifen? Mit
(assoc) natürlich!
(assoc) hätte von Ihnen gerne zwei Argumente: zuerst
einen Assoziationsschlüssel, und dann noch den Namen der
Assoziationsliste. Wenn Sie etwas über das Programm "biegen"
erfahren möchten, geben Sie also
(assoc 'biegen programm-info)
ein. Die Rückgabe lautet:
(BIEGEN (NAME "biegen.lsp")(DATUM 1 4 95)
(ZWECK "Macht Bogen aus Linie")(ZEILEN 36))
(assoc) gibt Ihnen immer die Unterliste einer Haupliste
zurück, deren erstes Element mit dem angegebenen Schlüssel
identisch ist. Da der Schlüssel immer mit zurückgegeben wird,
entfernt man ihn meistens durch die Kombination von
(cdr)
und
(assoc). Noch einmal:
(cdr(assoc 'biegen programm-info))
=>
((NAME "biegen.lsp")(DATUM 1 4 95)
(ZWECK "Macht Bogen aus Linie")(ZEILEN 36))
Unsere Datenbank ist aber schon keine einfache Assoziationsliste
mehr, da sie als Unterlisten wiederum Assoziationslisten enthält.
Wir können also auch folgende Frage an die Datenbank richten:
(cdr(assoc 'datum(cdr(assoc'biegen programm-info))))
=> (1 4 95)
Wenn ein Datenfeld nicht vorhanden ist, erhalten wir einfach nil.
(cdr(assoc 'anmerk(cdr(assoc'kleben programm-info))))
=> "Scheint nur nachts zu funktionieren!"
(cdr(assoc 'anmerk(cdr(assoc'biegen programm-info))))
=> nil
Die Abfrage ist uns aber doch ein wenig umständlich. Daher öffnen
wir noch einmal unsere Datenbankdatei und fügen die folgende
Funktionsdefinition als erste oder letzte Zeile hinzu:
(defun p-info(progr key)
(cdr
(assoc key
(cdr(assoc progr programm-info))
)
)
)
Jetzt können wir mit dieser Zugriffs-Funktion ganz einfach
Abfragen starten:
(p-info 'biegen 'datum)
=> (1 4 95)
(p-info 'kleben 'zweck)
=> ("Fügt zwei kollineare Linien zusammen")
; Wurden die beiden Programme am selben Tag geschrieben?
(equal
(p-info 'biegen 'datum)
(p-info 'kleben 'datum)
)
=> T
Sie sehen also, dass diese kleine Datenbank doch schon
recht erstaunliche Leistungen bringt. Wenn Sie sie ausbauen
und alle Ihre Programme darin eintragen, kann Sie (direkt
umgekehrt proportional zu Ihrem Gedächtnis) eine grosse Hilfe
in der AutoCAD-Kommandozeile sein.
Einen kleinen Schönheitsfehler hat die Datenbank aber noch -
vielleicht ist er Ihnen aufgefallen: Jede Rückgabe erfolgt in
Form einer Liste. Es wäre praktischer, wenn (ausser dem Datum,
das ja Listenform hat) alle Anworten ohne Klammern zurückgegeben
würden. Auch das lässt sich erreichen, man muss dann allerdings
die Datenbank aus dotted pairs aufbauen, die ja bereits in einem
der allersrsten Kapitel kurz angesprochen wurden.
Die gesamte Geometrie-Datenbank in AutoCAD besteht aus solchen
Assoziationslisten. Im nächsten Kapitel werden wir uns damit
näher befassen. Jetzt ist es aber an der Zeit, einmal unsere
Erkenntnisse über die komplexeren Listenfunktionen
zusammenzufassen:
-
(mapcar) wendet eine Funktion nacheinander auf die
als Argumente übergebene(n) Liste(n) an
-
Wenn die Listen, die an (mapcar) übergeben werden,
unterschiedliche Längen haben, dann wird die auszuführende
Funktion mit einer unterschiedlichen Anzahl von Argumenten
aufgerufen.
-
(mapcar) evaluiert alle seine Argumente
-
(lambda) definiert eine Funktion, die nicht an ein
Symbol gebunden wird (anonyme Funktion). Eine anonyme Funktion
ist zur direkten Evaluation bestimmt und kann nicht wiederverwendet
werden.
-
(lambda) wird sehr oft in Verbindung mit (mapcar)
eingesetzt.
-
(lambda) hat die gleiche Syntax wie (defun), es
fehlt allerdings das erste Argument von (defun).
-
(apply) führt eine Funktion aus und übergibt den
Inhalt der im zweiten Argument übergebenen Liste als Argumente
an die Ausführungsfunktion.
-
(foreach) ordnet einem Symbol nacheinander alle Elemente
einer Liste zu und evaluiert dann jeweils den übergebenen Ausdruck
-
(assoc) ist eine Funktion zur Bearbeitung von
Assoziationslisten. Es gibt die Unterliste einer Liste zurück,
deren erstes Element mit dem Assoziationsschlüssel identisch ist.
-
Assoziationslisten sind Datenbanken, bei denen Art, Anzahl,
Anordung usw. der Einträge völlig frei sind.
-
Die AutoCAD-Geometriedatenbank besteht aus Assoziationslisten.
-
Assoziationslisten können beliebig tief verschachtelt sein.