2011-10-03 39 views
4

我想能夠說(defvar x y)並且綁定到綁定到x而不是x的符號,但defvar只會綁定到符號x,這太糟糕了。我怎麼能沒有默認添加它的符號屬性呢?什麼是lisp的非破壞性版本?

回答

2

可以使用symbol-value訪問:

CL-USER> (defvar *sym* 'abc) 
*SYM* 
CL-USER> (setf (symbol-value *sym*) 100) 
100 
CL-USER> abc ;non-ANSI-portable, since ABC is undeclared 
100 

注意,這臺象徵的value cell,這是同它的動態綁定,所以爲了便攜訪問它,您可能需要使用symbol-value或(本地或全球)聲明變量special。全球範圍內使用defvar(不推薦用於非earmuffed符號)

CL-USER> (locally (declare (special abc)) 
      (+ abc 3)) 
103 

或:

CL-USER> (defvar abc) 
ABC 

(我不知道,其實需要CL實現您可以在本地做這樣的。這一點,雖然你通常是安全的假設未聲明的變量假設默認特)

1

除了馬蒂亞斯的回答:

你可以還使用set

T1> (defparameter *symbol* 'foo) 
*SYMBOL* 
T1> (set *symbol* 100) 
100 

因爲(set symbol value) == (setf (symbol-value symbol) value),即在對比setqsetfset評估其第一個參數。 (setq可能被解讀爲「set quoted」)set在Hyperspec中被標記爲廢棄,但由於我不會很快期待下一個CL標準,因此應該可以安全使用。


另外,我不認爲你必須以便攜訪問使用symbol-value或任何特殊的聲明 - 所有的實際目的,至少。 (雖然人們可能會認爲,從技術上講,因爲即使在本地特殊情況下也不能依賴修改的符號,也許變量不會通過symbol-value進行評估,但請參閱下面提到的Naggum帖子和Matthias的最後一句。)

確實如此,setq,setf,set et al。只保證修改符合實現的綁定。在頂層使用時,symbol-value將被修改,但不能依賴任何全局特殊聲明(或其他)發生(參見Naggum)。但通常,實現至少會使用symbol-value插槽評估新變量。這並不意味着必須使用symbol-value或本地/全局特殊聲明才能訪問symbol-value,但它的確實是的意思,即一個新的綁定的相同符號不會自動特殊,因爲它通過defparameter和朋友介紹的變量就是這種情況。

所以,雖然通常情況下,與全局特殊的變量:

T1> (let ((*symbol* 'bar)) 
     (symbol-value '*symbol*)) 
BAR 

一個綁定到全球特別將自身不能是特殊的:

T1> (let ((foo 101))  ; this new binding is lexical 
     (symbol-value 'foo)) ; so symbol-value refers to the outer special 
100 
T1> (let ((foo 101)) 
     foo)     ; evaluation of foo's new lexical binding 
101      ; doesn't look at the `symbol-value`. lexical 
          ; bindings are mere addresses at runtime. 

而這也是在可以使用當地的特殊聲明,以便參考foo的外部(非全局)特別約束:

T1> (let ((foo 101)) 
     foo)    ; our new lexical binding 
101 
T1> (let ((foo 101)) 
     (locally (declare (special foo)) 
     foo))   ; the outer special binding 
100 
T1> (let ((foo 101)) 
     (setq foo 102) ; modify the new lexical binding 
     foo) 
102 
T1> foo     ; doesn't modify the outer special binding 
100 
T1> (let ((foo 101)) 
     (locally (declare (special foo)) 
     (setq foo 102) ; modify the outer special binding 
     foo)) 
102 
T1> foo 
102 

據我所知,未定義的部分,或者至少是你應該預料到可移植性問題的部分,是這樣的頂層修改是否可以聲明某些東西(全局)特殊的。我想期望的行爲就是我在這裏展示的,但是如果變量將被全局聲明或者不是(或者甚至可以引入一個頂級詞法變量?),只要它至少在本地是特殊的, t需要本地聲明或symbol-value來訪問它。

另外,你應該考慮你是否真的需要你所要求的。很可能你想做的事情可以用一種更習慣的方式來解決(至少對於現代的Lispers來說),並且依賴於未定義的行爲不會被REPL使用的任何東西認爲是最好的風格。

+0

CMU CL _does_實際上是全局聲明一個由'setq' special創建的變量。 (這當然不適用於'(setf symbol-value)'。也許你的意思是這樣;我只是想澄清一下。) –

+0

Matthias:我的意思是,我希望*頂級'setq'是全球特有的還是本地的頂級(我認爲後者更普遍)。在這兩種情況下,人們不必使用「符號值」。但是(這就是我理解你的答案的原因),即使*不能保證,所以從理論上講,必須使用符號值纔是絕對可移植的。 (但那就是我*不會期望的。)也許我的答案的第二部分不夠清晰,但這些例子可能仍然有幫助。重點是可以使用'set',通常不需要'symbol-value'。 – danlei

+0

(「通常,沒有必要使用符號值」僅指這個問題,當然也有使用它的情況。) – danlei

相關問題