为什么不能直接push
或'(1 2 3)
等列表NIL
?
具体做法是: 为什么可以这样做
> (let ((some-list nil))
(push 42 some-list))
(42)
但不要做像
这样的事情(push 42 nil)
或
(push 42 '(1 2 3))
此实施背后的推理是什么?
答案 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
。