Woher wissen, wann oder wann nicht das einfache Anführungszeichen vor Variablennamen verwendet werden soll?

31

Ich habe das Folgende:

(setq some-variable "less")

Ich bin verwirrt, warum ich das einfache Anführungszeichen mit verwenden muss, boundpaber nicht mit bound-and-true-p.

Beispiel 1:

(when (boundp 'some-variable) 
   (message "some-variable is %s" some-variable))

Ergebnis:

"eine Variable ist weniger"

Beispiel 2a:

(when (bound-and-true-p some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))

Ergebnis:

"eine Variable ist weniger"

Beispiel 2b:

(when (bound-and-true-p 'some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))

Ergebnis:

und: Falsches Typargument: symbolp, (zitiere eine Variable)

Kaushal Modi
quelle
5
Erwähnenswert ist, dass setqsteht set quotedund 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 ( setqeine wichtige Ausnahme).
Shosti
2
FWIW, bound-and-true-pist ein dummes Makro. Oder besser gesagt, sein Name ist dumm. 99,99% der Zeit , wenn Sie wollen, tun (and (boundp 'FOO) FOO)Sie es tun , um den Wert zu verwendenFOO . Sie tun es nicht nur, um einen Wahrheitswert zu erhalten. (1) Das Makro wird nicht benötigt - der Code, den es ersetzt, ist trivial und klein. (2) Der Name ist irreführend - es geht um den Variablenwert, nicht nur darum zu testen, ob der Variablenwert ist oder nicht nil.
Drew

Antworten:

24

Kurze Antwort

Wenn Sie versuchen, die Variable selbst zu verwenden, verwenden Sie 'some-variable. Wenn Sie versuchen, den in der Variablen gespeicherten Wert zu verwenden, verwenden Sie some-variable.

  • boundp verwendet das Symbol, um alles zu betrachten, was gebunden werden kann, einschließlich Funktionen. Es ist nur wichtig, ob es ein Symbol gibt, das passt, und nicht, was der Wert ist.
  • bound-and-truep verwendet var und gibt den Wert zurück. In diesem Fall müssen Sie der Funktion den Wert des Symbols mitteilen. Wenn kein Symbol var gebunden ist oder der Wert null ist, wird null zurückgegeben.

Erläuterung

Informationen zur manuellen Definition finden Sie im Handbuch .

'und (quote ...)beide führen in emacs-lisp den gleichen zweck aus.

Ziel ist es, das nicht bewertete Formular an die Umgebung weiterzugeben, anstatt es zu bewerten.

Nehmen wir in Ihrem Beispiel an, wir hätten das Folgende oben

(setq some-variable "less") ;; Rather than just 't for clarity

Dann läuft die Auswertung wie folgt ab:

(when (boundp 'some-variable) 
   (message "some-variable is %s" some-variable))
;; ==> (boundp 'some-variable) ; 't
;; ==> some-variable is "less"

Während ohne ein Zitat:

(when (boundp some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))
;; ==> (boundp "less") ; "less" is not a variable. -> Error

Lisp wertet Formulare so aus, wie sie erreicht sind, indem Sie das Formular, das Sie nicht auswerten möchten, in Anführungszeichen setzen, damit die tatsächliche Variable (oder Liste oder Funktionsname) übergeben wird.

Jonathan Leech-Pepin
quelle
Vielen Dank! Ihre Antwort ließ mich in die Quellen von beiden springen und half mir, die Lösung zu finden. Ich habe auch meine Frage mit klaren Beispielen aktualisiert.
Kaushal Modi
6
Ich bin froh, dass dies der Operation geholfen hat, aber es beantwortet die Frage nicht wirklich (in einer Weise, die für andere Leute nützlich ist, die die gleiche Frage haben). Sie erklären nur, dass Symbole in Anführungszeichen gesetzt werden müssen oder ausgewertet werden. Sie erklären nicht, warum dies nicht der Fall ist, bound-and-truepund die Frage war, warum ich bei der Verwendung zitieren muss, boundpaber nicht bei der Verwendung bound-and-truep.
Tarsius
@tarsius Ich schließe tatsächlich die Unterscheidung zwischen dem boundpErfordernis eines Symbols (nicht bewertet) und bound-and-truepdem Erfordernis des Werts der Variablen in den Aufzählungspunkten (bearbeitet nach der ersten Antwort) ein
Jonathan Leech-Pepin
Ich denke, es ist wichtig zu erwähnen, warum das so ist (Makros können wählen, nicht zu bewerten), anstatt nur zu erwähnen, dass der Doc-String dies sagt. Ich denke, das ist eine sehr gute Frage und dass boundp vs. bound-and-true-p nur ein Beispiel ist. Worauf es wirklich ankommt, ist der Wunsch, etwas über Bewertungsregeln zu lernen.
Tarsius
@tarsius Werden die Bewertungsregeln durch diese Antwort nicht erklärt? Zumindest grundlegende Fragen, die nur das Zitat betreffen ... Ihre Antwort ist definitiv vollständiger, geht aber weit über das Thema hinaus, nicht wahr?
T. Verron
16

Ein nicht funktionsfähiges Symbol wird als Name einer Variablen behandelt. In (function variable) functionist in Funktionsposition (nach der öffnenden Klammer) und variablenicht. 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-variablegebundenen Variablen gespeichert ist" und nicht "das my-variableals Variable gebundene Symbol .

Warum verhält es bound-and-truepsich 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-psieht 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, nilwenn my-variablenicht boundpoder 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. quoteist 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-pauch 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 quoteverhindert werden, dass ein Symbol ausgewertet wird.

Aber warum ist bound-and-true-pein Makro, während boundpes 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 boundpArgument automatisch in Anführungszeichen gesetzt würde.

bound-and-true-pwird 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-pkann 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 '.

Tarsius
quelle
Erstaunlich gut beantwortet.
Charles Ritchie
2

Aus dem Quellcode von boundp:

DEFUN ("boundp", Fboundp, Sboundp, 1, 1, 0,
      doc: /* Return t if SYMBOL's value is not void.
Note that if `lexical-binding' is in effect, this refers to the
global value outside of any lexical scope.  */)

boundperwartet a symbolals eingabe. 'some-variableist ein Symbol für die Variable some-variable.

Aus dem Quellcode von bound-and-true-p:

(defmacro bound-and-true-p (var)
  "Return the value of symbol VAR if it is bound, else nil."
  `(and (boundp (quote ,var)) ,var))

bound-and-true-perwartet a variableals eingabe.

Innerhalb des bound-and-true-pMakros erhält es das Symbol, indem es tut (quote ,var). Also, wenn die Eingabe ist some-variable, (quote ,var)wird sich ergeben 'some-variable.

Aber wenn ich den Eingang geben 'some-variablean bound-and-true-p, erhalte ich die Fehlermeldung: and: Wrong type argument: symbolp, (quote some-variable)da das Makro ein Symbol nicht erwartet ( 'some-variable) am Eingang.

Kaushal Modi
quelle
Nur ein Heads-Up. ''symbol macht Sinn. Es bedeutet (quote (quote symbol)). Der Grund, warum Sie eine Fehlermeldung erhalten, ist, dass dies kein gültiges Argument für ist boundp.
Malabarba
@ Malabarba Danke. Ich habe die Korrektur vorgenommen.
Kaushal Modi