2011-01-08 13 views
5

Il codice qui sotto ha z come variabile locale, ma si comporta come se si tratta di una globale:Gli elenchi di proprietà in Common Lisp si riferiscono ad alcuni stati globali?

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

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

mi aspetterei l'uscita di essere

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

ma quando si esegue con SBCL I vedi

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

Perché è questo il caso? Questo comportamento è peculiare agli elenchi di proprietà?

+0

Possibile duplicato del [la persistenza dei dati imprevisto] (http://stackoverflow.com/questions/18790192/Inattesa-persistenza-dei dati) –

risposta

6

In foo, z è associato all'espressione letterale '(stuff nil). La funzione altera distruttivamente z, modificando in modo distruttivo il valore del letterale. Come si comporta LISP in circostanze come questa dipende dall'implementazione. Alcune implementazioni modificheranno obbedientemente il valore letterale (come nel tuo caso). Altre implementazioni posizionano letterali in posizioni di memoria di sola lettura e falliscono se si tenta di modificare tali valori letterali.

per ottenere il comportamento desiderato, utilizzare COPY-LIST per fare una copia del letterale che può essere modificato in modo sicuro:

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

Penso che il modo più idiomatico sarebbe usare 'LISTA', come in' (let ((z (lista 'stuff nil))) ...) ' – Ken