Pergunta

The code below has z as a local variable, yet it behaves as if it is a global:

(defun foo (m)
  (let ((z '(stuff nil)))
    (push m (getf z 'stuff))
    (print z)))

(foo 1)
(foo 2)
(foo 3)

I would expect the output to be

(STUFF (1)) 
(STUFF (2)) 
(STUFF (3)) 
T

but when running it with SBCL I see

(STUFF (1)) 
(STUFF (2 1)) 
(STUFF (3 2 1)) 
T

Why is this the case? Is this behaviour peculiar to property lists?

Foi útil?

Solução

In foo, z is bound to the literal expression '(stuff nil). The function destructively alters z, thus destructively changing the value of the literal. How LISP behaves in circumstances like this is implementation-dependent. Some implementations will obediently alter the literal value (as in your case). Other implementations place literals in read-only memory locations and will fail if you attempt to modify those literals.

To get the desired behaviour, use COPY-LIST to make a copy of the literal that can be safely modified:

(defun foo (m)
  (let ((z (copy-list '(stuff nil))))
    (push m (getf z 'stuff))
    (print z)))
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top