Reputation: 127
While learning scheme commands from the official documentation https://www.scheme.com/tspl4/start.html#./start:h9
What is going on here:
> (define ls1 '((ignored) ignored))
#<unspecified>
> ls1
((ignored) ignored)
> (set-car! (cdr ls1) 'a)
#<unspecified>
> ls1
((ignored) a)
This is expected. But when I use a define another list
which 'looks' like ls1
, in the following manner, why does set-car!
replace both occurrences of ignored
with a
? I understand that the define end (cons 'ignored '())
is most likely the reason for the behavior but I can't formulate any explanation for this.
> (define end (cons 'ignored '()))
#<unspecified>
> end
(ignored)
> (define ls2 (cons end end))
#<unspecified>
> ((set-car! (cdr ls2) 'a)
#<unspecified>
> ls2
((a) a)
>
Upvotes: 1
Views: 62
Reputation: 71119
Let's say you had
(define end1 (cons 'ignored '()))
(define ls1 (cons end1 (cons 'ignored '())))
(define end2 (cons 'ignored '()))
(define ls2 (cons end2 end2))
As is readily seen, ls2
refers to the same entity named end2
with both it parts, the car
and the cdr
.
Quite differently, ls1
's two parts are referring each to a different entity - the car
refers to end1
and the cdr
- to results of another invocation of the same cons
form:
(eq? end2 end2) ;=> #t
(eq? (car ls2) (cdr ls2)) ;=> #t
(eq? (car ls1) (cdr ls1)) ;=> #f
(equal? (car ls1) (cdr ls1)) ;=> #t
The eq?
returning #t
means the two arguments are actually the same object in memory. So when you alter the contents of a memory-resident object, you alter the contents of a memory-resident object. With ls2
, there's only one location involved, the one referred to by end2
:
(eq? (cdr ls2) end2) ;=> #t
(set-car! (cdr ls2) 'a) ; changes `end2` to '(a)
Otherwise, each new invocation of cons
is guaranteed to create and return a new location in memory, even if holding equal?
contents. Hence altering one copy does not affect the other, situated at another place in memory:
(eq? (cdr ls1) end1) ;=> #f
(set-car! (cdr ls1) 'a) ; `end1` is unchanged
Upvotes: 2