如何知道何时或何时不使用变量名前的单引号?


31

我有以下内容:

(setq some-variable "less")

我很困惑为什么必须将单引号与一起使用,boundp而不将其与一起使用bound-and-true-p

范例1:

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

结果:

“多变少”

示例2a:

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

结果:

“多变少”

示例2b:

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

结果:

和:错误的类型参数:symbolp,(引用一些变量)


5
值得一提的是setq代表set quoted,而原本是一个宏扩展到(set 'some-variable "less")。通常,Elisp对于带引号和不带引号的参数并不一致,但是任何需要与变量而不是值交互的函数(不是宏)都将其引号引起来(这setq是一个主要的例外)。
shosti 2014年

2
FWIW,bound-and-true-p是一个愚蠢的宏。或者说,它的名字很愚蠢。的99.99%的时间,当你想这样做(and (boundp 'FOO) FOO),你做它的使用价值FOO。您不只是为了获得真实价值而这样做。(1)不需要宏-宏替换的代码很小且很小。(2)名称令人误解-它与变量值有关,而不仅仅是测试变量值是否为nil
2014年

Answers:


24

简短答案

如果您尝试使用变量本身,请使用'some-variable。如果您尝试使用存储在变量中的值,请使用some-variable

  • boundp使用symbol,因此它将查看可以绑定的任何内容,包括函数。它只关心是否有匹配的符号,而不关心值是什么。
  • bound-and-truep使用var并返回值。在这种情况下,您需要向函数提供符号的值。如果没有符号var绑定,或者值为nil,则它将返回nil。

说明

有关手册的定义,请参见手册

'(quote ...)这两个执行的Emacs Lisp中同样的目的。

这样做的目的是将未经评估的形式传递给周围环境,而不是对其进行评估。

在您的示例中,假设我们有以下更高的方面

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

然后评估如下:

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

而没有引号:

(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会在到达表单时对表单进行评估,通过引用阻止评估的表单,以便传递实际的变量(或列表或函数名称)。


谢谢!您的回答使我同时了解了两者的来源,并帮助我提出了解决方案。我还用清晰的示例更新了我的问题。
Kaushal Modi 2014年

6
我很高兴这对操作员有所帮助,但实际上并不能回答问题(对其他有相同问题的人很有用)。您仅说明符号必须加引号,否则将对其进行评估。您没有解释为什么不是这种情况,bound-and-truep问题是为什么在使用boundp时必须引用而不是引用bound-and-truep
tarsius 2014年

@tarsius我实际上在boundp要求符号(未bound-and-truep评估)和需要变量的值之间加上了区别(在初始答案后编辑)
Jonathan Leech-Pepin 2014年

我认为必须提及为什么会这样(宏可能会选择不评估),而不是仅仅提到文档字符串这么说。我认为这是一个非常好的问题,并且boundp与bound-and-true-p只是一个例子。这个问题真正归结为对学习评估规则的渴望。
tarsius 2014年

@tarsius答案未解释评估规则吗?至少基本的仅涉及引号...您的答案肯定更完整,但这远远超出了主题,不是吗?
T. Verron 2014年

16

处于非功能位置的符号被视为变量的名称。In (function variable) function在功能位置(在左括号后面),但variable不在。除非明确引用的变量被其值替换。

如果要写的话(boundp my-variable),这意味着“是符号存储在变量值中,my-variable绑定为变量”,而不是“符号存储my-variable为变量。

那么为什么bound-and-truep表现不同呢?

这是一个宏,常规(函数)求值规则在这里不适用,宏可以自由决定是否以及何时对它们的参数求值。宏实际上所做的是以某种方式转换参数并将结果作为列表返回,然后对其进行评估。转换和最终评估发生在不同的时间,称为宏扩展时间和评估时间。

这是定义的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))

这使用了与lisp宏不同的阅读器宏(更多内容请参见下文)。为了不使此问题进一步复杂化,请不要使用任何阅读器宏:

(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))

如果你写

(bound-and-true-p my-variable)

首先是“翻译”为

(and (boundp 'my-variable) my-variable)

然后评估返回的结果nil是否my-variableboundp,否则返回的值my-variable(当然也可以是nil)。


您可能已经注意到扩展不是

(and (boundp (quote my-variable)) my-variable)

如我们所料。quote是一种特殊形式,而不是宏或函数。像宏一样,特殊形式可以对其参数做任何事情。这种特殊的特殊形式只是返回其参数(这里是一个符号),而不是该符号的变量值。这实际上是这种特殊形式的唯一目的:防止评估!宏无法自行执行此操作,因此需要使用宏quote来执行此操作。

那怎么了'?它是一个阅读器宏,如上所述,它与lisp宏不同。虽然宏用于转换代码/数据,但阅读器宏在读取文本时会更早使用,以便将文本转换为代码/数据。

'something

是的简写形式

(quote something)

`实际定义中使用的bound-and-true-p也是阅读器宏。如果它像那样引用一个符号,`symbol则等价于'symbol,但是当它被用来引用一个列表时,`(foo bar ,baz)它在以前缀为形式的形式中表现不同,

`(constant ,variable)

相当于

(list (quote constant) variable))

这应该回答一个问题,为什么有时会评估(用其值替换)未引用的符号,而有时却不评估;宏可以quote用来防止符号被评估。

但是为什么bound-and-true-pboundp却不是?我们必须能够确定是否将直到运行时才知道的任意符号绑定为符号。如果boundp参数被自动引号,则不可能。

bound-and-true-p用于确定是否定义了已知变量,如果已定义,则使用其值。如果库对第三方库具有可选的依赖关系,则这很有用:

(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可以被定义为一个函数并要求引用参数,但是因为它用于预先了解宏的变量是用来避免键入的情况'


令人惊讶的好答案。
Charles Ritchie

2

从的源代码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.  */)

boundp期望a symbol作为输入。'some-variable是变量的符号some-variable

从的源代码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-p期望a variable作为输入。

bound-and-true-p宏内部,通过执行操作获得符号(quote ,var)。因此,如果输入为some-variable(quote ,var)将导致'some-variable

但是,当我将输入提供'some-variable给时bound-and-true-p,会出现错误:and: Wrong type argument: symbolp, (quote some-variable)因为宏'some-variable在输入处不期望使用符号()。


单挑。''symbol 确实有道理。这意味着(quote (quote symbol))。出现错误的原因是它不是的有效参数boundp
马拉巴巴2014年

@Malabarba谢谢。我做了更正。
2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.