Common lisp (push x nil)VS(push x存储空列表的位置)
为什么不能直接将Common lisp (push x nil)VS(push x存储空列表的位置),common-lisp,Common Lisp,为什么不能直接将推送到'(1 2 3)或NIL之类的列表上 具体而言: 为什么可以这样做 > (let ((some-list nil)) (push 42 some-list)) (42) 但是不要做像这样的事情 (push 42 nil) 或 此实现背后的原因是什么?使用宏push第二个参数需要修改。以下是一些例子: 让我们创建两个变量: (defparameter *v* (list 2 4)) (defparameter *v-copy* *v*) 然后我们按0 (
推送到'(1 2 3)
或NIL
之类的列表上
具体而言:
为什么可以这样做
> (let ((some-list nil))
(push 42 some-list))
(42)
但是不要做像这样的事情
(push 42 nil)
或
此实现背后的原因是什么?使用宏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*)))
如果你的例子是有效的,它应该做什么呢?让我们先做nil:
(macroexpand '(push 42 nil))
; ==> (setq nil (cons 42 nil))
这就像对待任何其他变量一样对待nil
,如果这起作用nil
将不再是空列表。它应该是一个包含一个元素的列表,42
,并且与()
的值不同。通常,Lispnil
是一个常量,不能进行变异。我曾经创建过一个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
功能的类型。它不起作用,也没有意义。无论如何,如果将文本数据'(1 2 3)
更改为'(43 1 2 3)
时,您是否希望每次计算(1 2 3)
时都能得到(43 1 2 3)
?我想这将是改变常数的唯一真正效果。如果允许,则应允许您将4
重新定义为5
,以便对4
或(+2)
进行求值,显示结果5
对于宏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*)))
如果你的例子是有效的,它应该做什么呢?让我们先做nil:
(macroexpand '(push 42 nil))
; ==> (setq nil (cons 42 nil))
这就像对待任何其他变量一样对待nil
,如果这起作用nil
将不再是空列表。它应该是一个包含一个元素的列表,42
,并且与()
的值不同。通常,Lispnil
是一个常量,不能进行变异。我曾经创建过一个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
功能的类型。它不起作用,也没有意义。无论如何,如果将文本数据'(1 2 3)
更改为'(43 1 2 3)
时,您是否希望每次计算(1 2 3)
时都能得到(43 1 2 3)
?我想这将是改变常数的唯一真正效果。如果允许,则应允许您将4
重新定义为5
,以便对4
或(+2)
进行求值,显示结果5
PUSH
是一个位置修改宏。它CONS
将一个值赋给存储在该位置的任何对象(变量是位置的一种),并将结果存储在该位置。如果你不想修改一个地方,你可以直接调用CONS
。你希望(push 42'(1 2 3))
做什么?@Rainer:我希望push
首先检查第二个参数是nil
还是一个列表,如果是,则返回(CONS x nil)
或(CONS x'(1 2 3))
。但正如jkiiski所指出的,我完全忽略了显而易见的:cons
odes,这很好。对。推应该有副作用。因为它应该与变量一起工作,所以它需要是一个宏来执行此操作。PUSH
是一个修改宏的地方。它CONS
将一个值赋给存储在该位置的任何对象(变量是位置的一种),并将结果存储在该位置。如果你不想修改一个地方,你可以直接调用CONS
。你希望(push 42'(1 2 3))
做什么?@Rainer:我希望push
首先检查第二个参数是nil
还是一个列表,如果是,则返回(CONS x nil)
或(CONS x'(1 2 3))
。但正如jkiiski所指出的,我完全忽略了显而易见的:cons
odes,这很好。对。推应该有副作用。因为它应该和变量一起工作,所以它需要是一个宏来完成。谢谢你的详细回答。我知道nil在CL中是一个文本/常量。我希望push
检查第二个arg是否为nil
,如果是,则返回类似(cons x nil)
@Frankpush
的值不会用于它的返回值,而是通过改变一个位置而产生的副作用。在(let((v nil))(push 1 v))
事件中,使用push
的原因不存在了,因为您不使用v
,它超出了范围。您可能已经编写了(cons1nil)
。感谢您的详细回答。我知道nil在CL中是一个文本/常量。我希望push
检查第二个arg是否为nil
,如果是,则返回类似(cons x nil)
@Frankpush
的值不会用于它的返回值,而是通过改变一个位置而产生的副作用。在(let((v nil))(push 1v))
事件中,使用push
的原因已经不存在了