Dies ist eine gute Frage, und eine, bei der Common Lisp ziemlich verwirrend sein kann. Der Grund dafür ist, dass Common Lisp aus historischen Gründen zwei Namensräume hat - einen für Funktionen und einen für Werte. Um dies zu ermöglichen, gibt es zwei verschiedene Auswertungsregeln für die Kopfposition einer Funktionsanwendung und für den Rest - die erste bewertet ein Symbol als Funktionsnamen, und die zweite bewertet ein Symbol als Variablenreferenz. Es gibt natürlich Fälle, in denen der Wert tatsächlich eine Funktion ist - zum Beispiel, wenn Sie eine mapcar
-Funktion schreiben, möchten Sie etwas wie das Folgende tun:
(defun my-mapcar (f l)
(if (null l)
'()
(cons (f (car l)) (my-mapcar f (cdr l)))))
aber das wird nicht funktionieren - es wird sich über f
als unbekannte Funktion beschweren. Für diese Fälle gibt es eine spezielle Funktion namens funcall
, die eine Funktion und ein Argument für die Funktion empfängt und die Funktion wie üblich anwendet - und da funcall
eine einfache Funktion ist, werden ihre Argumente wie üblich bewertet (als Werte). Also sollte das obige durch Verwendung von funcall
behoben werden:
(defun my-mapcar (f l)
(if (null l)
'()
(cons (funcall f (car l)) (my-mapcar f (cdr l)))))
Wie Sie wahrscheinlich jetzt vermuten, gibt es die gegenteiligen Fälle - wenn Sie etwas als Funktion evaluieren möchten und nicht als Wert. Zum Beispiel funktioniert dies nicht:
(my-mapcar 1+ '(1 2 3))
weil es auf die 1+
-Variable verweist und nicht auf die Funktion. Für diese Fälle gibt es eine spezielle Form namens function
, die ihren Inhalt als Funktion auswertet und ihn als Wert zurückgibt:
(my-mapcar (function 1+) '(1 2 3))
und es kann mit #'
abgekürzt werden:
(my-mapcar #'1+ '(1 2 3))
Das ist nicht das Ende dieser Geschichte - um ein paar Beispiele zu nennen:
-
In einigen Fällen kann ein einfacher zitierter Name als Funktion funktionieren - zum Beispiel funktioniert '1+
im letzten Beispiel - aber dies ist eine Art Hack, der nur global gebundene Namen sehen kann, daher ist #'
fast immer besser
-
Ein ähnlicher Hack kann mit lambda
verwendet werden - also können Sie (my-mapcar '(lambda (x) (1+ x)) '(1 2 3))
verwenden, tatsächlich könnten Sie (list 'lambda '(x) '(1+ x))
verwenden, was sogar noch schlimmer ist (und meines Wissens nicht tragbar), aber die Verwendung von (lambda (x) (1+ x))
funktioniert, da es implizit in ein #'
verpackt ist (versuchen Sie, eine lambda
-Form als Makro zu erweitern, und Sie werden es sehen). Ein verwandter Hack macht es in Ordnung, einen lambda
-Ausdruck als Kopf einer Funktionsanwendung zu verwenden (was eine der Dinge ist, die Sie versucht haben).
-
let
etc. binden lokale Werte, und in einigen Fällen möchten Sie lokale Funktionen binden - dafür gibt es neue Bindungskonstrukte: flet
und labels
Wenn all dies seltsam und/oder übermäßig kompliziert aussieht, dann sind Sie nicht allein. Es ist einer der Hauptunterschiede zwischen Common Lisp und Scheme. (Der Unterschied führt dann zu Änderungen in gängigen Idiomen in beiden Sprachen: Schemecode neigt dazu, wesentlich häufiger höhere Ordnungsfunktionen zu verwenden als Common Lisp-Code. Wie üblich bei diesen religiösen Fragen argumentieren einige Leute zugunsten dessen, was CL macht, und behaupten, dass höhere Ordnungsfunktionen verwirrend sind, deshalb mögen sie die explizite Erinnerung im Code.)