4
votes

I try to figure out something intersting that happen in Scheme:

(define last-pair
     (lambda (x)
       (if (null? (cdr x))
           x
           (last-pair (cdr x)))))

When I defined foo in this way:

(define foo
  (lambda ()
    (let ((s (list 'he 'said:)))
      (set-cdr! (last-pair s)
                (list 'ha 'ha))
      s)))

and run foo 3 times, I got:

(he said: ha ha)
(he said: ha ha)
(he said: ha ha)

But when I defined foo in this way:

(define foo
  (lambda ()
    (let ((s '(he said:))) 
      (set-cdr! (last-pair s)
                (list 'ha 'ha))
      s)))

and run foo 3 times, I got:

(he said: ha ha)
(he said: ha ha ha ha)
(he said: ha ha ha ha ha ha)

But why? My first thought was that we build always new list in the first foo, and in the second we don't. But I didn't understood how it actully working. Scheme define adress in the second foo, and do what? Is it define as a list also in the second foo? or a symbol?

Thanks.

1
What interpreter of Scheme are you using? I couldn't reproduce that behavior in Racket - since it forces me to always use mlist for creating mutable lists, as the '(a b c) syntax produces immutable listsÓscar López
@Óscar López: I use Dr.Scheme or chezSchemeAdam Sh
That's an old version now it's called Racket and, among many other new things, it forbids the mutation of lists unless the lists are explicitly declared to be mutable. Maybe you found a bug? I'd suggest that you try with Racket, if it's not too much of a hassleÓscar López
But as Adam is talking about scheme, not racket, we should consider the scheme language standard, not racket. It works this way in other Scheme implementations as well.Vladimir F

1 Answers

3
votes

Literal lists ('(foo bar baz), as opposed to (list 'foo 'bar 'baz)) are not allowed to be mutated. If you do, that "is an error" (i.e., the behaviour is undefined).

In this case, what you are observing is that the literal '(he said:) is being reused over and over, with the understanding that it's not going to get mutated. Since you violated that understanding, you get the weird behaviour you saw.

In contrast, when you use (list 'he 'said:), a new list is returned every time.