Adam Sh
Adam Sh

Reputation: 8577

Scheme - define list vs symbol

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.

Upvotes: 4

Views: 771

Answers (1)

C. K. Young
C. K. Young

Reputation: 223153

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.

Upvotes: 3

Related Questions