我正在学习lisp和我在这方面相当新手,所以我想知道…
如果我这样做:
(defparameter *list-1* (list 1 2))
(defparameter *list-2* (list 2 3))
(defparameter *list-3* (append *list-1* *list-2*))然后
(setf (first *list-2*) 1)
*list-3*我将得到(%1%2%1% 4)
我知道这是因为append将“节省资源”并为第一个块创建一个新列表,但实际上将只指向第二个块,因为如果我这样做:
(setf (first *list-1*) 0)
*list-3*我将安装(1 2 1 4)更符合逻辑的(0 2 1 4)
所以我的问题是,在lisp中还有其他类似的情况,你们这些黑带口吃者如何知道如何处理这种不直观或不一致的东西?
发布于 2009-01-09 03:55:24
一种防御策略是避免共享结构。
(defparameter *list-3* (append *list-1* *list-2* '()))或
(defparameter *list-3* (append *list-1* (copy-list *list-2*)))现在,新*list-3*的结构是全新的,对*list-3*的修改不会影响*list-2*,反之亦然。
发布于 2009-01-09 03:45:04
append函数必须复制它的第一个参数,以避免修改现有的数据结构。因此,您现在有两个看起来像(1 2 ...)的列表片段,但它们是不同列表的一部分。
一般而言,任何列表都可以是任何其他列表的尾部,但您不能将单个列表对象用作多个列表的头部。
发布于 2009-01-09 03:51:09
你必须从cons单元格的角度来考虑列表。当您定义列表1和列表2时,它类似于:
(defparameter *list-1* (cons 1 (cons 2 nil)))
(defparameter *list-2* (cons 2 (cons 3 nil)))然后,在添加以下内容时:
(defparameter *list-3* (cons 1 (cons 2 *list-2*)))基本上,cons单元格由两部分组成:一个值( car)和一个指针( cdr)。Append被定义为不更改第一个列表,因此它被复制,但随后最后一个cdr (通常为空)被更改为指向第二个列表,而不是第二个列表的副本。如果您愿意销毁第一个列表,您可以使用nconc。
试试这个:
(defparameter *list-3* (nconc *list-1* *list-2*))然后观察*list-1*的值,它是(1 2 2 3),就像*list-3*一样。
一般规则是,非破坏性函数(append)不会销毁现有数据,而破坏性函数(nconc)则会。然而,未来的破坏性功能((setf cdr))并不是第一个非破坏性功能的责任。
https://stackoverflow.com/questions/426991
复制相似问题