要求解释集合车的意外行为!并在计划中定义

时间:2018-03-30 18:29:48

标签: scheme lisp

从官方文档https://www.scheme.com/tspl4/start.html#./start:h9

学习方案命令

这里发生了什么:

> (define ls1 '((ignored) ignored))
#<unspecified>
> ls1
((ignored) ignored)
> (set-car! (cdr ls1) 'a)
#<unspecified>
> ls1
((ignored) a)

这是预期的。但是,当我使用另一个list来定义&#39;看起来&#39;与ls1一样,以下方式,为什么set-car!会将ignored的两次出现替换为a?我理解define end (cons 'ignored '())很可能是行为的原因,但我无法对此做出任何解释。

> (define end (cons 'ignored '()))
#<unspecified>
> end
(ignored)
> (define ls2 (cons end end))
#<unspecified>
> ((set-car! (cdr ls2) 'a)
#<unspecified>
> ls2
((a) a)
> 

1 个答案:

答案 0 :(得分:1)

假设你有

(define end1 (cons 'ignored '()))
(define ls1 (cons end1 (cons 'ignored '())))
(define end2 (cons 'ignored '()))
(define ls2 (cons end2 end2))

很容易看出,ls2指的是名为end2相同的实体,其中包含carcdr两个部分。

完全不同的是,ls1的两个部分将每个部分引用到另一个实体 - car引用end1cdr - 指向另一个实体的结果相同的cons形式:

(eq? end2 end2) ;=> #t
(eq? (car ls2) (cdr ls2)) ;=> #t
(eq? (car ls1) (cdr ls1)) ;=> #f
(equal? (car ls1) (cdr ls1)) ;=> #t

eq?返回#t表示两个参数实际上是内存中的同一个对象。因此,当您更改内存驻留对象的内容时,更改内存驻留对象的内容。使用ls2时,只涉及一个位置,{{1}引用的位置{1}}:

end2

否则,每次(eq? (cdr ls2) end2) ;=> #t (set-car! (cdr ls2) 'a) ; changes `end2` to '(a) 的新调用都会保证在内存中创建并返回 new 位置,即使保留cons内容也是如此。因此,改变一个副本不会影响另一个副本,位于内存中的另一个位置:

equal?