2011-01-08 10 views
5

El código de abajo tiene z como una variable local, sin embargo, se comporta como si se trata de un mundial:¿Las listas de propiedades en Common Lisp se refieren a algún estado global?

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

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

que sería de esperar que la salida sea

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

pero cuando se ejecuta con SBCL I ver

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

¿Por qué es este el caso? ¿Es este comportamiento peculiar de las listas de propiedades?

+0

Posible duplicado de [persistencia inesperada de datos] (http://stackoverflow.com/questions/18790192/unexpected-persistence-of-data) –

Respuesta

6

En foo, z está obligado a la expresión literal '(stuff nil). La función altera de forma destructiva z, lo que modifica de forma destructiva el valor del literal. Cómo se comporta LISP en circunstancias como esta depende de la implementación. Algunas implementaciones alterarán obedientemente el valor literal (como en su caso). Otras implementaciones colocan literales en ubicaciones de memoria de solo lectura y fallarán si intenta modificar esos literales.

Para obtener el comportamiento deseado, utilice COPY-LIST para hacer una copia de lo literal que puede ser modificado de manera segura:

(defun foo (m) 
    (let ((z (copy-list '(stuff nil)))) 
    (push m (getf z 'stuff)) 
    (print z))) 
+7

Creo que la forma más idiomática sería usar 'LIST', como en' (let ((z (list 'stuff nil))) ...) ' – Ken