通过阅读有关 Lisp 的介绍性材料,我现在认为以下内容是相同的:
(list 1 2 3)
'(1 2 3)
但是,从我在 Clojure 和 Emacs Lisp 中使用带引号的形式时遇到的问题来看,它们并不相同。你能告诉我有什么区别吗?
主要区别在于quote
防止评估元素,而list
不会:
用户=> '(1 2 (+ 1 2)) (1 2 (+ 1 2)) 用户=> (列表 1 2 (+ 1 2)) (1 2 3)
出于这个原因(以及其他原因),在描述文字集合时使用向量是惯用的 clojure:
用户=> [1 2 (+ 1 2)] [1 2 3]
在 Common Lisp 中,带引号的对象是常量文字数据。您不应修改此数据,因为后果是不确定的。可能的后果是:修改共享数据,尝试修改只读数据,可能会发出错误信号,它可能正常工作,......
对于列表:
'(1 2 3)
上面是一个常量列表,它将由读者构造并对其自身进行评估,因为它被引用了。如果它出现在 Lisp 代码中,编译器会以某种方式将这些数据嵌入到 FASL 代码中。
(quote (1 2 3))
是另一种写法。
(list 1 2 3)
这是对 Common Lisp 函数的调用,带有LIST
三个参数和。评估结果是一个全新的列表。1
2
3
(1 2 3)
相似的:
'(1 . 2) and (cons 1 2)
'#(1 2 3) and (vector 1 2 3)
一种是文字数据,另一种是构造这种数据结构的函数调用。
引用列表(例如'(1 2 3)
)应谨慎对待(通常为只读)。(请参阅 SO 回答何时在 Lisp 中使用 'quote和何时在 Lisp 中使用 'quote)。
(list 1 2 3)
将“cons”一个新的列表,独立于所有其他列表。
您可以在手册中nconc
看到使用带引号的列表的陷阱示例。
而且,您可能知道,当您调用时'list
- 显然会根据引用列表的内容对参数进行评估。并'quote
采用单个参数,而不是'list
s 可变数量的参数。
(list (+ 1 2) 3) --> (3 3)
(quote ((+ 1 2) 3)) --> ((+ 1 2) 3)
它们的关系可以类似于使用“函数名称”和 的函数调用funcall
。
当您不知道在运行时会获得什么功能时,您可以使用funcall
.
当您不知道在运行时可能会获得什么元素时,您可以使用list
.
对于像我这样因为存在而感到困惑backquote
并默认将其视为报价的人。
backquote
不是quote
这是一个阅读器宏,可以扩展为quote
,list
或其他:
(macroexpand ''(1 2));=> '(1 2)
(macroexpand '`(1 2));=> '(1 2)
(macroexpand '`(1 ,2));=> (list 1 2)
(macroexpand '`(1 ,@foo));=> (cons 1 foo)
(macroexpand '`(1 ,@foo 2));=> (cons 1 (append foo '(2)))