Lisp 中的 (list nil) 和 '(nil) 有什么区别?

What's the difference between (list nil) and '(nil) in Lisp?

首先,让我说我是 Lisp 的初学者。老实说我已经是新手有一段时间了,但是还有很多东西我不太了解。

当我在写 的时候,我在我的代码中发现了一个奇怪的错误。

这是一个函数,它将 return 列表 (0 1 ... n) 附加到列表 e 。它在整个过程中使用 rplacd 来跟踪最后一个元素,以避免最终调用 last.

例如,(foo 4 '(x)) returns (0 1 2 3 4 x).

"head" 存储在 a 中,这不是简单的 nil,因为只有一个 nil,并且永远不会复制它(如果我理解正确),因此我不能简单地附加到 nil.

(defun foo (n e)
    (let* ((a (list nil)) (tail a))
        (loop for i to n
              do (rplacd tail (setf tail (list i)))
              finally (rplacd tail (setf tail e))
              (return (cdr a)))))

(defun bar (n e)
    (let* ((a '(nil)) (tail a))
        (loop for i to n
              do (rplacd tail (setf tail (list i)))
              finally (rplacd tail (setf tail e))
              (return (cdr a)))))

这些函数之间的唯一区别是 (list nil) 替换为 bar 中的 '(nil)。虽然 foo 按预期工作,但 bar 总是 returns nil.

我最初的猜测是因为 a 的原始 cdr 确实是 nil,并且引用列表可能被认为是常量。但是,如果我这样做 (setf x '(nil)) (rplacd x 1),我会按预期得到 (nil . 1),所以我一定至少有部分错误。

计算时,'(nil) 和 (list nil) 生成相似的列表,但前者在源代码中出现时可以被视为常量。你不应该对 Common Lisp 中的常量引用列表执行任何破坏性操作。参见 http://l1sp.org/cl/3.2.2.3 and http://l1sp.org/cl/quote。特别是,后者说 "The consequences are undefined if literal objects (including quoted objects) are destructively modified."

引用的数据被认为是常量。如果你有两个函数:

(defun test (&optional (arg '(0)))
  (setf (car arg) (1+ (car arg)))
  (car arg))

(defun test2 ()
  '(0))

这两个函数都使用常量列表 (0) 对吧?

  1. 实现可以选择不改变常量:

    (test) ; ==> Error, into the debugger we go
    
  2. 实现可以 cons 相同的列表两次(reader 可能会这样做)

    (test2) ; ==> (0)
    (test)  ; ==> 1
    (test)  ; ==> 2
    (test)  ; ==> 3
    (test2) ; ==> (0)
    
  3. 实现可以看到和hench save是一样的space:

    (test2) ; ==> (0)
    (test)  ; ==> 1
    (test)  ; ==> 2
    (test)  ; ==> 3
    (test2) ; ==> (3)
    

事实上。最后两个行为可能会在同一实现中发生,具体取决于正在编译的函数。

在 CLISP 中,这两个函数的工作原理相同。我还看到在使用 SBCL 反汇编时常量实际上发生了变异,所以我想知道它是否在编译时常量折叠 (cdr '(0)) 并且根本不使用变异列表。这真的无关紧要,因为两者都被认为是良好的 "undefined" 行为。

这部分 from CLHS 很短

The consequences are undefined if literal objects (including quoted objects) are destructively modified.