Ein nicht funktionsfähiges Symbol wird als Name einer Variablen behandelt. In (function variable)
function
ist in Funktionsposition (nach der öffnenden Klammer) und variable
nicht. Sofern nicht explizit angegeben, werden Variablen durch ihre Werte ersetzt.
Wenn Sie schreiben (boundp my-variable)
würden, würde dies bedeuten , dass "das Symbol ist, das im Wert der als Variable my-variable
gebundenen Variablen gespeichert ist" und nicht "das my-variable
als Variable gebundene Symbol .
Warum verhält es bound-and-truep
sich also anders?
Dies ist ein Makro und die normalen (Funktions-) Bewertungsregeln gelten hier nicht. Makros können frei entscheiden, ob und wann ihre Argumente bewertet werden. Tatsächlich transformieren Makros die Argumente auf irgendeine Weise und geben das Ergebnis als Liste zurück, die dann ausgewertet wird. Die Transformation und die endgültige Auswertung erfolgen zu unterschiedlichen Zeiten, die als Makroexpansionszeit und Auswertungszeit bezeichnet werden.
So bound-and-true-p
sieht die Definition von aus:
(defmacro bound-and-true-p (var)
"Return the value of symbol VAR if it is bound, else nil."
`(and (boundp (quote ,var)) ,var))
Dies verwendet Reader-Makros, die sich von Lisp-Makros unterscheiden (mehr dazu weiter unten). Um dies nicht weiter zu erschweren, verwenden Sie keine Reader-Makros:
(defmacro bound-and-true-p (var)
"Return the value of symbol VAR if it is bound, else nil."
(list 'and (list 'boundp (list 'quote var)) var))
Wenn du schreibst
(bound-and-true-p my-variable)
das wird erstmal "übersetzt" nach
(and (boundp 'my-variable) my-variable)
und dann wird das als Rückgabe gewertet, nil
wenn my-variable
nicht boundp
oder sonst der Wert von my-variable
(was natürlich auch sein kann nil
).
Sie haben vielleicht bemerkt, dass die Erweiterung nicht war
(and (boundp (quote my-variable)) my-variable)
wie wir es erwartet hätten. quote
ist eine spezielle Form, kein Makro oder eine Funktion. Sonderformen können wie Makros mit ihren Argumenten alles machen. Diese spezielle Form gibt einfach ihr Argument, hier ein Symbol, anstelle des variablen Wertes des Symbols zurück. Das ist eigentlich der einzige Zweck dieses speziellen Formulars: die Verhinderung der Auswertung! Makros können das nicht alleine, sie müssen es benutzen quote
.
Also, was ist '
los mit ? Es ist ein Reader-Makro , das, wie oben erwähnt, nicht mit einem Lisp-Makro identisch ist . Während Makros zum Transformieren von Code / Daten verwendet werden, werden Lesemakros früher beim Lesen von Text verwendet, um diesen Text in Code / Daten zu transformieren.
'something
ist eine Kurzform für
(quote something)
`
In der eigentlichen Definition von wird bound-and-true-p
auch ein Reader-Makro verwendet. Wenn ein Symbol in Anführungszeichen gesetzt wird `symbol
, ist dies äquivalent zu 'symbol
, aber wenn eine Liste in Anführungszeichen gesetzt wird `(foo bar ,baz)
, verhält es sich anders, als wenn Formulare, denen ein Präfix vorangestellt ,
ist, ausgewertet werden.
`(constant ,variable)
ist äquivalent zu
(list (quote constant) variable))
Dies sollte die Frage beantworten, warum nicht zitierte Symbole manchmal ausgewertet werden (durch ihre Werte ersetzt werden) und manchmal nicht. Mit Makros kann quote
verhindert werden, dass ein Symbol ausgewertet wird.
Aber warum ist bound-and-true-p
ein Makro, während boundp
es nicht ist? Wir müssen feststellen können, ob beliebige Symbole, die erst zur Laufzeit bekannt sind, als Symbole gebunden sind. Dies wäre nicht möglich, wenn das boundp
Argument automatisch in Anführungszeichen gesetzt würde.
bound-and-true-p
wird verwendet, um zu bestimmen, ob eine bekannte Variable definiert ist, und wenn ja, ihren Wert zu verwenden. Dies ist nützlich, wenn eine Bibliothek eine optionale Abhängigkeit von einer Drittanbieter-Bibliothek aufweist, wie in:
(defun foo-get-value ()
(or (bound-and-true-p bar-value)
;; we have to calculate the value ourselves
(our own inefficient or otherwise undesirable variant)))
bound-and-true-p
kann als Funktion definiert werden und erfordert die Angabe des Arguments in Anführungszeichen, da dies jedoch für Fälle gedacht ist, in denen Sie im Voraus wissen, welche Variable Sie für ein Makro verwenden, um zu vermeiden, dass Sie das eintippen müssen '
.
setq
stehtset quoted
und ursprünglich ein Makro, das erweitert wurde(set 'some-variable "less")
. Im Allgemeinen ist Elisp in Bezug auf Argumente in Anführungszeichen und nicht in Anführungszeichen nicht besonders konsistent, aber jede Funktion (kein Makro), die mit einer Variablen anstelle eines Werts interagieren muss, verwendet ihr Argument in Anführungszeichen (setq
eine wichtige Ausnahme).