首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >LISP非常简单的列表问题

LISP非常简单的列表问题
EN

Stack Overflow用户
提问于 2009-01-09 03:34:41
回答 6查看 653关注 0票数 3

我正在学习lisp和我在这方面相当新手,所以我想知道…

如果我这样做:

代码语言:javascript
复制
(defparameter *list-1* (list 1 2))
(defparameter *list-2* (list 2 3))
(defparameter *list-3* (append *list-1* *list-2*))

然后

代码语言:javascript
复制
(setf (first *list-2*) 1)
*list-3*

我将得到(%1%2%1% 4)

我知道这是因为append将“节省资源”并为第一个块创建一个新列表,但实际上将只指向第二个块,因为如果我这样做:

代码语言:javascript
复制
(setf (first *list-1*) 0)
*list-3*

我将安装(1 2 1 4)更符合逻辑的(0 2 1 4)

所以我的问题是,在lisp中还有其他类似的情况,你们这些黑带口吃者如何知道如何处理这种不直观或不一致的东西?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2009-01-09 03:55:24

一种防御策略是避免共享结构。

代码语言:javascript
复制
(defparameter *list-3* (append *list-1* *list-2* '()))

代码语言:javascript
复制
(defparameter *list-3* (append *list-1* (copy-list *list-2*)))

现在,新*list-3*的结构是全新的,对*list-3*的修改不会影响*list-2*,反之亦然。

票数 4
EN

Stack Overflow用户

发布于 2009-01-09 03:45:04

append函数必须复制它的第一个参数,以避免修改现有的数据结构。因此,您现在有两个看起来像(1 2 ...)的列表片段,但它们是不同列表的一部分。

一般而言,任何列表都可以是任何其他列表的尾部,但您不能将单个列表对象用作多个列表的头部。

票数 4
EN

Stack Overflow用户

发布于 2009-01-09 03:51:09

你必须从cons单元格的角度来考虑列表。当您定义列表1和列表2时,它类似于:

代码语言:javascript
复制
(defparameter *list-1* (cons 1 (cons 2 nil)))
(defparameter *list-2* (cons 2 (cons 3 nil)))

然后,在添加以下内容时:

代码语言:javascript
复制
(defparameter *list-3* (cons 1 (cons 2 *list-2*)))

基本上,cons单元格由两部分组成:一个值( car)和一个指针( cdr)。Append被定义为不更改第一个列表,因此它被复制,但随后最后一个cdr (通常为空)被更改为指向第二个列表,而不是第二个列表的副本。如果您愿意销毁第一个列表,您可以使用nconc。

试试这个:

代码语言:javascript
复制
(defparameter *list-3* (nconc *list-1* *list-2*))

然后观察*list-1*的值,它是(1 2 2 3),就像*list-3*一样。

一般规则是,非破坏性函数(append)不会销毁现有数据,而破坏性函数(nconc)则会。然而,未来的破坏性功能((setf cdr))并不是第一个非破坏性功能的责任。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/426991

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档