在Lisp中复制和修改列表的标题 [英] duplicating and modifying the head of a list of list, in Lisp

查看:130
本文介绍了在Lisp中复制和修改列表的标题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习Lisp.我希望将新列表添加到列表的列表中,例如((1 1 1)(0 0 0)),其中该列表集合的新头是根据前一个头来计算的.

I'm learning Lisp. I wish to add a new list to a list of list, say ((1 1 1) (0 0 0)), where the new head of this list collection is computed based on the previous head.

这是我在Slimv中使用sbcl在REPL环境中尝试过的事情:

Here's what I tried, in the REPL environment in Slimv with sbcl:

> (defvar *ll* (list (list 1 1 1) (list 0 0 0)))
*LL*
> *ll*
((1 1 1) (0 0 0))
> (push (car *ll*) *ll*)
((1 1 1) (1 1 1) (0 0 0))
> (setf (nth 2 (car *ll*)) 2)
2
> *ll*
((1 1 2) (1 1 2) (0 0 0))

如上所示,我只想修改第一个列表的最后一个元素,但是不知何故,第二个列表的最后一个元素也被更改了.

As shown above, I only wanted to modify the last element of the first list, but somehow the last element of the second list was also changed.

我注意到,如果我改为输入一个全新的列表,那么结果将有所不同:

I noticed that if instead I push into a brand-new list, then the result is different:

> (defvar *lll* (list (list 1 1 1) (list 0 0 0)))
*LLL*
> (push '(1 1 1) *lll*)
((1 1 1) (1 1 1) (0 0 0))
> (setf (nth 2 (car *lll*)) 2)
2
> *lll*
((1 1 2) (1 1 1) (0 0 0))

我想知道是什么导致了这些不同的结果,以及如何实现将新列表添加到列表列表中的结果,其中结果列表集合的新头是根据前一个头来计算的".谢谢!

I'd like to know what causes these different results, and how to achieve the result that "adds a new list to the list of list, where the new head of resulting list collection is computed based on the previous head." Thanks!

推荐答案

(car *ll*)(cadr *ll*)是相同的列表

(car *ll*) and (cadr *ll*) are the same list

> (defvar *ll* (list (list 1 1 1) (list 0 0 0)))
*LL*
> *ll*
((1 1 1) (0 0 0))
> (push (car *ll*) *ll*)
((1 1 1) (1 1 1) (0 0 0))
> (setf (nth 2 (car *ll*)) 2)
2
> *ll*
((1 1 2) (1 1 2) (0 0 0))

如上所示,我只想修改第一个元素的最后一个元素 列表,但是不知何故第二个列表的最后一个元素也是 改变了.

As shown above, I only wanted to modify the last element of the first list, but somehow the last element of the second list was also changed.

那里只有一个对象,然后您对其进行了修改.它与您拥有某种结构化数据类型(实际上是什么是cons单元,但只有两个字段的结构化数据类型)没有什么不同.如果您有一个人员列表,然后将第一个人添加到列表中,则仍然只有一个人员.该人仅出现在列表中的两个位置.如果您更改此人的名字,您将在两个地方都看到它.如果将 *print-circle* 设置为t.

There's only one object there, and you modified it. It's not really any different than if you had some sort of structured data type (and really, what is a cons cell but a structured datatype with just two fields). If you have a list of people, and then you add the first person to the list again, there's still just one person; the person just appears two places in the list. If you change the name of the person, you'll see it in both places. You can actually see the shared structure if you set *print-circle* to t.

CL-USER> (defvar *ll* (list (list 1 1 1) (list 0 0 0)))
*LL*
CL-USER> *ll*
((1 1 1) (0 0 0))
CL-USER> (push (car *ll*) *ll*)
((1 1 1) (1 1 1) (0 0 0))
CL-USER> *ll*
((1 1 1) (1 1 1) (0 0 0))
CL-USER> (setf *print-circle* t)
T
CL-USER> *ll*
(#1=(1 1 1) #1# (0 0 0))

使用#1=…#1#的表示法表示 same 对象是列表的第一和第二个元素.

The notation using #1=… and #1# indicates that the same object is the first and second element of the list.

我希望将新列表添加到列表列表中,例如((1 1 1) (0 0 0)), 该列表集合的新标题是根据 前任负责人. …

I wish to add a new list to a list of list, say ((1 1 1) (0 0 0)), where the new head of this list collection is computed based on the previous head. …

> (push (car *ll*) *ll*)
((1 1 1) (1 1 1) (0 0 0))

您说您想将 new 列表添加到列表列表中,但您不是要添加 new 列表.您要添加(car *ll*),这是您从(list 1 1 1)开始创建的列表.如果要复制列表,则需要显式复制,例如,使用

You said that you wanted to add a new list to a list of lists, but you're not adding a new list; you're adding (car *ll*) which is the list you created at the beginning with (list 1 1 1). If you want to copy the list, you'll need to copy it explicitly, e.g., with copy-list:

> (push (copy-list (car *ll*)) *ll*)
((1 1 1) (1 1 1) (0 0 0))

请勿修改文字数据!

顺便说一句,由于要修改 literal 列表'(1 1 1),因此第二个代码块中的操作实际上是未定义的行为.

Don't modify literal data!

As an aside, what you're doing in your second code block is actually undefined behavior, since you're modifying the literal list '(1 1 1).

> (defvar *lll* (list (list 1 1 1) (list 0 0 0)))
*LLL*
> (push '(1 1 1) *lll*)            ; '(1 1 1) is literal data.
((1 1 1) (1 1 1) (0 0 0))
> (setf (nth 2 (car *lll*)) 2)     ; (car *lll*) is literal data, and you're modifying it!
2
> *lll*
((1 1 2) (1 1 1) (0 0 0))

请参见我的答案. >意外的数据持久性,详细说明了为什么会出现问题.

See my answer to Unexpected persistence of data for more about why this can be problematic.

这篇关于在Lisp中复制和修改列表的标题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆