【发布时间】:2020-03-03 22:18:51
【问题描述】:
这段代码来自emacs缓冲区slime-repl sbcl:
CL-USER> (consp 'notdefinedsymbol)
无
CL-USER> (find-if #'consp '('notdefinedsymbol))
'未定义符号
如果 consp 返回 nil 那么为什么 find-if 会像 consp 返回一个真值一样呢?
【问题讨论】:
标签: common-lisp quote
这段代码来自emacs缓冲区slime-repl sbcl:
CL-USER> (consp 'notdefinedsymbol)
无
CL-USER> (find-if #'consp '('notdefinedsymbol))
'未定义符号
如果 consp 返回 nil 那么为什么 find-if 会像 consp 返回一个真值一样呢?
【问题讨论】:
标签: common-lisp quote
(consp 'notdefinedsymbol) consp 在操作符位置是#'consp 函数的符号,因此它的参数(quote notdefinedsymbol),缩写为'notdefinedsymbol 需要在应用之前进行评估。 (quote x) 对数据 x 进行赋值,因此在我们的例子中,参数变为符号 notdefinedsymbol。它不是cons,而是symbolp,因此结果是nil
第二个你有(find-if #'consp '('notdefinedsymbol)),因为find-if是一个函数,它会评估它的参数。 #'consp 计算为函数对象,'('notdefinedsymbol) 是 (quote ((quote notdefinedsymbol))) 的缩写,计算结果。一如既往,它评估了它的论点((quote notdefinedsymbol))。它是一个包含一个元素的列表,它本身就是一个包含两个元素的列表,符号quote 和notdefinedsymbol。由于(consp '(quote notdefinedsymbol) ; ==> t find-if 评估为(quote notdefinedsymbol) 并且一些CL 打印机将缩写两个元素的列表,其中第一个元素是quote,其方式与阅读器宏相同并打印'notdefinedsymbol,但它仍然是一个列表两个元素,因为它不是代码,而是数据。
您的错误当然是嵌套引号。如果你这样做了,你会得到预期的结果:
(find-if #'consp '(notdefinedsymbol)) ; ==> nil
【讨论】:
(consp 'a) - 首先评估函数参数。所以我们有:'a 计算结果为:a。那是一个原子,因此是NIL。
(find-if #'consp '('a)) 也首先评估参数。但是对于列表的第一个参数,它测试'a 是否是一个缺点。是的,因为那是(quote a)(只评估列表的外部',而不是a前面的内部,因此'a。
a = notdefinedsymbol.
【讨论】:
您的电话:(find-if #'consp '('not-defined-symbol)) 与(即由读者扩展为)(find-if (function consp) (quote ((quote not-defined-symbol)))) 相同。参数(quote ((quote not-defined-symbol))) 被评估为列表((quote not-defined-symbol))(即一个包含两个符号quote 和not-defined-symbol 的列表的列表)。 Find-if 遍历那个外部列表,测试内部,这是一个缺点,consp,它说 true,然后返回它。
你想做的最有可能是:(find-if #'consp '(not-defined-symbol)),与(find-if (function consp) (quote (not-defined-symbol))相同。注意:没有嵌套引号。
查看the docs for quote 和the CLHS chapter about evaluation 以获得更好的理解。
【讨论】: