Nun zur Funktion
(lambda), die in gewisser Weise ähnlich
arbeitet wie
(defun).
(lambda) bindet den
Funktionscode aber nicht an ein Symbol. Daher nennt man eine
so erzeugte Funktion eine 'anonyme Funktion'. Wozu werden anonyme
Funktionen gebraucht? Sie werden dann benutzt, wenn klarsteht,
dass sie nur einmal verwendet werden und nicht von anderen
Stellen des Programms erreichbar sein müssen.
Mit
(defun) angelegt würden sie nach dem Gebrauch nur
noch Speicherplatz verbrauchen. Anonyme Funktionen werden
hingegen da erzeugt, wo sie gebraucht werden, und verschwinden
nach Gebrauch wieder - man könnte Sie also auch als Einweg-Funktionen
bezeichnen. Da keine Bindung an ein Symbol hergestellt wird,
müssen Sie gleichzeitig mit ihrer Definition ausgeführt werden.
Der Aufruf von
(lambda) ist fast identisch mit dem
Gebrauch von
(defun). Lediglich das erste Argument von
(defun), der Symbolname, fehlt bei
(lambda).
Keines der Argumente von
(lambda) wird sofort evaluiert.
Im vorigen Kapitel haben wir besprochen, wie man eine Reihe
von Zahlen in einer Liste mit der Funktion
(1+ ...)
inkrementieren kann:
(mapcar '1+ '(10 14 3 41 65))
=> (11 15 4 42 66)
Was aber, wenn wir nicht um 1, sondern um 2 erhöhen wollen?
Natürlich könnten wir eine Funktion namens
(2+ ...)
definieren und das Symbol übergeben. Oder wir könnten
(mapcar ...) mit einer zusätzlichen Liste aufrufen,
die n-mal die Zahl 2 enthält, und dann das Symbol
+
übergeben. Die beiden Listen müssten allerdings exakt gleich
lang sein. Beide Verfahren, wie nachstehend gezeigt, würden
funktionieren, wären aber umständlich:
(defun 2+(zahl)(+ zahl 2))
(mapcar '2+ '(10 14 3 41 65))
=> (12 16 5 43 67)
; oder
(mapcar '+
'(10 14 3 41 65)
'(2 2 2 2 2)
)
Wenn wir aber sicher sind, dass es sich nicht lohnt, die
Funktion
(2+ ...) mit
(defun) zu erzeugen und
abzulegen, da sie nicht noch einmal gebraucht wird,
dann sollte man sie mit
(lambda) direkt in den
(mapcar)-Ausdruck integrieren:
(setq zahlen '(4 2 11 14 3 8 10 3))
=> (4 2 11 14 3 8 10 3)
(mapcar'(lambda(arg)(+ arg 2))zahlen)
=> (6 4 13 16 5 10 12 5)
Beachten Sie, dass der gesamte
(lambda)-Ausdruck
quotiert an
(mapcar) übergeben werden muss, damit er
nicht sofort evaluiert wird. Er soll ja erst dann evaluiert
werden, wenn er auf zahlen angewendet wird. Wenn Sie noch
einmal die Beispiele mit
(mapcar) und
(+)
vergleichen, werden Sie folgenden Zusammenhang erkennen:
Die Anwendung von
(+) auf zwei oder mehr Listen kann
direkt über
(mapcar) erfolgen. Soll eines der Argumente für
(+) jedoch konstant sein und nicht bei jedem Aufruf von
(+) neu aus einer Liste entnommen werden, dann ist eine
(lambda)-Konstruktion angebracht. Machen wir uns das an
einem kombinierten Beispiel klar. Es soll wieder die Funktion
(+) auf 2 Listen angewendet werden. Gleichzeitig soll
aber das Ergebnis noch um 1 inkrementiert werden. Es wird
also die Funktion
(+) immer mit 3 Argumenten aufgerufen.
Zwei der Argumente werden jedesmal den Listen entnommen, das
dritte Argument ist konstant 1. Wir können das so formulieren:
(setq zahlen1 '(4 2 11 14 3 8)
zahlen2 '(6 6 2 11 18 5)
)
(mapcar
'(lambda(arg1 arg2 / )
(+ arg1 arg2 1)
)
zahlen1
zahlen2
)
Das Ergebnis dieser Operation wäre dann
(11 9 14 22 14).
Man hätte hier aber auch mit einem doppelten
(mapcar) zum
Zuge kommen können:
(mapcar'1+(mapcar'+ zahlen1 zahlen2))
hätte hier sogar mit etwas weniger Schreibaufwand zum Ergebnis
geführt.
Sicherlich werden Sie sich jetzt schon mal gefragt haben, ob man
denn so etwas auch zu etwas Sinnvollem gebrauchen kann. Mann
kann durchaus! Wenn Sie z.B. mit den Längen von Dateinamen hantieren,
dann kann es sein, dass Sie genau das vorige Beispiel nachexerzieren
müssen (Länge des Namens + Länge der Extension + 1 für den Punkt
dazwischen). Und wenn Sie demnächst die Programmierer-Pflicht
absolviert haben und sich der Kür zuwenden, dann werden Sie
feststellen, dass sie den doppelten
(mapcar) im Schlaf
turnen und Ihr Ehrgeiz doch eher darin besteht, sich an einem
mehrfach verschachtelten rekursiven
(mapcar'(lambda...))
zu versuchen.
Ich denke, man kann sagen, dass das Konzept eines
(lambda)-Ausdrucks so ziemlich das wichtigste Konzept in
AutoLisp überhaupt ist. So wichtig, dass ich diesem Thema auf den
Fortgeschrittenen-Seiten
gleich mehrere weitere Kapitel gewidmet habe.