I'm confused about destructive operations in Scheme. Let's say I have a list and some destructive procedures defined in the global environment:
(define a '(a b c))
(define (mutate-obj x)
(set! x '(mutated)))
(define (mutate-car! x)
(set-car! x 'mutated))
(define (mutate-cdr! x)
(set-cdr! x 'mutated))
Then we have the following expression evaulation:
(mutate-obj! a) a => (a b c)
(mutate-car! a) a => (mutated b c)
(mutate-cdr! a) a => (mutated . mutated)
Why isn't set!
having an effect on a
outside its procedure when both set-car!
and set-cdr!
have? Why isn't the expression on the first line evaluating to (mutated)
? How does all of this really work?
The first example isn't working as you imagined. Although both the x
parameter and the a
global variable are pointing to the same list, when you execute (set! x '(mutated))
you simply set x
(a parameter local to the procedure) to point to a different list, and a
remains unchanged. It'd be different if you wrote this:
(define (mutate-obj)
(set! a '(mutated)))
Now a
gets mutated inside the procedure. The second and third procedures are modifying the contents of the a
list, also pointed by x
, so the change gets reflected "outside" once the procedure returns.