(推x无)VS(推x位 - 存储空列表)

时间:2017-04-02 09:45:29

标签: common-lisp

为什么不能直接push'(1 2 3)等列表NIL

具体做法是: 为什么可以这样做

> (let ((some-list nil))
    (push 42 some-list))

(42)

但不要做像

这样的事情
(push 42 nil)

(push 42 '(1 2 3))

此实施背后的推理是什么?

1 个答案:

答案 0 :(得分:4)

使用宏push,第二个参数需要是要修改的位置。以下是一些例子:

让我们做两个变量:

(defparameter *v* (list 2 4))
(defparameter *v-copy* *v*)

然后我们推0

(push 1 *v*) ; ==> (1 2 4)
*v-copy*     ; ==> (2 4) (unaltered)

; the reason is that the variable is changed, not its value
(macroexpand '(push 1 v))
; ==> (setq v (cons 1 v))

push可以使用其他东西作为第二个参数。让我们试试cons

(push 3 (cdr *v-copy*))
*v-copy*  ; ==> (2 3 4)
; since the tail of *v* is the *v-copy* *v* is changed too
*v*       ; ==> (1 2 3 4)

(macroexpand-1 '(push 2 (cdr *v-copy*)))
; ==> (rplacd v (cons 2 (cdr *v-copy*)))

如果您的示例有效,它应该做什么?让我们先做零:

(macroexpand '(push 42 nil))
; ==> (setq nil (cons 42 nil))

这与任何其他变量一样对待nil,如果这有效nil将永远不再是空列表。它应该是包含一个元素42和不同于​​()的值的列表。在Common Lisp nil是常量,不能变异。我创建了一个lisp,其中nil是一个变量,就像任何其他变量一样,并且一个小错误重新定义nil使得程序表现得很奇怪,没有明显的理由。

让我们试试您的文字引用列表。

(macroexpand '(push 42 (quote (1 2 3))))
; ==> (let ((tmp (1 2 3)))
;      (funcall #'(setf quote) (cons 42 'tmp) tmp))

push宏似乎不区分特殊格式quote和已设置其setf函数的类型。它不起作用,没有意义。无论如何,如果将文字数据nil更改为'(1 2 3),则改变绑定'(43 1 2 3)的方式相同,那么每次评估(43 1 2 3)时,您都希望获得(1 2 3)从那里?我想这将是改变常数的唯一真实效果。如果允许,则应允许您将4重新定义为5,以便评估4(+ 2 2)显示结果5