我正在努力理解为什么当我更改列表中的某些值而其他Lisp数据却没有更改时,某些Lisp数据会更改

问题描述

我正在苦苦挣扎的两个人理解为什么当我更改l1列表的值时,double-args宏会更改结果列表中的值,而double-list却没有。让我展示一些更清晰的步骤。 我用值'(1 2 3 4),

定义了列表l1
(setq l1 '(1 2 3 4))

然后我在下面加载此代码

    (defmacro double-args (&rest args)
`(let ((ret nil))
    ( dolist (x,@args )
        (setq ret (append ret (list x x))))
    
   ret) )

(defun macroteste (&rest x) (double-args x))

 ;; first simple macro example:

(defmacro double-list (a-list)
  (let ((ret (gensym)))
   `(let ((,ret nil))
     (dolist (x,a-list)
      (setq,ret (append,ret (list x x)))),ret)))

 ;; use the macro:

 (defun doublelistmacro (x)
  (double-list x))

此后,我执行了宏,将宏teste与列表l1并存储在l2中

 (setq l2 (macroteste l1))

然后我用arg l1执行了doublelistmacro并存储在l3中

 (setq l3 (doublelistmacro l1))

所以我来自二等 (((1 2 3 4)(1 2 3 4)) 从l3开始 (1 1 2 2 3 3 4 4)

然后我更改了l1的第二个值, (setf(nth 1 l1)9) 我得到了这些结果:

l1

(1 9 3 4)

l2

(((1 9 3 4)(1 9 3 4))

l3

(1 1 2 2 3 3 4 4)

为什么我更改l1时l2也更改了,而l3没有更改?

解决方法

首先,请注意:在代码中,您不应修改文字常量,例如'(1 2 3 4)。效果是不确定的。

在您的情况下,差异可以归结为这一点

CL-USER 2 > (let ((foo (list 1 2 3 4)))
              (let ((l1 (list foo foo))
                    (l2 (loop for e in foo append (list e e))))
                (values l1 l2)))
((1 2 3 4) (1 2 3 4))
(1 1 2 2 3 3 4 4)

第一个列表l1是一个新列表,其原始列表以其元素为两倍。 第二个列表l2是一个全新的列表。

如果更改原始列表,它将在第一个结果中可见->它直接将它们作为元素。

它在第二个列表中将不可见,因为该列表是完全新鲜的。

还请注意,宏使问题变得更加复杂。因此,它们也没有什么意义。