我是 Scheme 的新手,如果我用 set-car!/set-cdr! (甚至在本地)父列表也被修改。这是一个例子,我的意思是:
(define my-list '(1 2 3 4 5)) ; Original list
(define (function list) ; Some example function
(let ((copy list))
(set-car! copy 'new)
(display copy)
)
(function my-list); will display (new 2 3 4 5)
my-list; but the original is changed "forever" and will be also '(new 2 3 4 5)
我的问题是:
有没有办法复制原始列表并仅在其上工作,所以最后不要更改原始列表?
最佳答案
您的代码 (let ((copy list))
允许通过名称副本访问列表。所以当你 set-car!
复制,你其实是set-car!
'ing 原始列表。
类似 lisp 的语言中的突变现象起初有点令人困惑。
由于您发现的原因,通常应避免突变。列表的一部分和漂浮的东西。这是因为在内部,列表中的每个节点都有两个部分 - car
它的值是否可能指向另一个列表,它是cdr
是它后面的部分 - 通常这是一些类似于 car
中的值的东西.
这使用 SRFI1 的列表复制功能解决了您的问题
(let ((copy (list-copy list))))
这是复制列表的一种方法(制作新列表)。这段代码并不完整。当我们在内部查看它时,它会在每个递归调用中添加一个列表片段。每个新列表部分的片段来自哪里? cdr
通过调用 (list-copy (cdr list))
生成,而 car
只是采取 - 不是复制! - 从另一个列表。
(define (list-copy list)
(if (null? list) '() (cons (car list) (list-copy (cdr list)))))
实验时您的结果是您列表中的汽车
copy
借自my-list
.这是一个更合适的版本:
(define (full-copy list)
(if (null? list)
'()
(if (list? list)
(cons (full-copy (car list)) (full-copy (cdr list)))
list)))
只有
car
的代码已经改变。现在,这辆车被改造到了。唯一借用的部分是数字(所以当数字更特别时,这个副本就不行了)。我不确定 srfi1 版本是如何工作的。let 语句只将一个标识符绑定(bind)到一个对象 - 对象不会被复制,您只是有另一种访问它的方法。因此,任何更改(使用突变,如以“!”结尾的函数)都会影响两者。
关于list - Scheme中列表(或其他内容)的副本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20802629/