在emacs lisp中使用nconc的奇怪行为

时间:2014-08-06 09:57:10

标签: emacs elisp

我有以下功能(简化为该版本):

(defun append-test (xs)
 (let ((ys `(foo ,(nconc `(bar) xs))))
    (nconc ys `((baz)))))

如果我多次评估函数(append-test '((foo))),列表的大小会不断增加,但我无法理解为什么。 nconc修改原始列表,但由于原始列表是函数参数或let-variable,因此每次调用都应重新创建它们,对吧?这里发生了什么?

2 个答案:

答案 0 :(得分:2)

如果您将`(bar)更改为(list 'bar),则代码每次都会返回相同的结果。

nconc修改所有参数,但最后一个参数。显然,如果第一个参数是'(bar),那么函数定义中包含的引用列表将被修改,我们希望看到您看到的结果。显然使用不包含任何逗号的反引号表达式等同于使用引用列表。

实际上,下面的代码保留了反引号,但是为列表的cdr添加了一个无意义的表达式。显然,这使得它在每次调用函数时都会分配一个新列表,因此每次都会返回相同的结果:

(defun append-test (xs)
 (let ((ys `(foo ,(nconc `(bar . ,(ignore)) xs))))
    (nconc ys `((baz)))))

答案 1 :(得分:1)

我被这个咬了。以下是一些导致的错误。

http://comments.gmane.org/gmane.emacs.bugs/50783

http://lists.gnu.org/archive/html/emacs-bug-tracker/2011-09/msg00220.html

这个问题似乎是lisp开发人员的成文。 : - )

根据我的理解,lisp评估分为两个阶段:

  1. 阅读:静态分配存储并将表单读入内存的读卡器。
  2. 评估:评估阅读表格。
  3. quote怎么样?

    quote只返回读取表单而不进行评估。

    隐含地,

    1. 评估quote表单时,它只返回已分配的阅读器 直接对象。
    2. 当重新评估quote表单(即函数调用等)时,它返回 同一个读者分配对象。
    3. quote不分配新内存
    4. 钽哒!