2011-01-08 47 views
5

下面的代碼有z作爲一個局部變量,但它的行爲就好像它是一個全球性的:Common Lisp中的屬性列表是指全局狀態嗎?

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

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

我希望可以將輸出爲

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

但SBCL我運行它時見

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

爲什麼會出現這種情況?這種行爲是屬性列表特有的嗎?

+0

[數據意外的持久性(可能的重複http://stackoverflow.com/questions/18790192/unexpected-persistence-of-data) – 2015-10-23 20:06:50

回答

6

fooz被綁定到文字表達式'(stuff nil)。該功能破壞性地改變z,從而破壞性地改變文字的值。 LISP在這種情況下的行爲如何依賴於實現。一些實現會乖乖地改變字面值(如你的情況)。其他實現將文字放置在只讀內存位置,如果嘗試修改這些文字,將會失敗。

爲了獲得所需的行爲,使用COPY-LIST使字面的副本可以安全地修改:

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

我認爲更習慣的方式是使用`LIST`,就像在`(let((z(list'stuff nil)))...) – Ken 2011-01-08 06:51:58