2012-12-26 25 views
6

我知道當你想在Lisp中進行動態/全局綁定時,可以使用defparameter或defvar。我也知道你可以使用defun參數列表或let語句來製作詞彙綁定,幾乎無處不在。當我在LISP中使用簡單的setf語句時會發生什麼?

什麼我不知道是它到底是什麼我做當我提出這樣的,其中x未聲明或代碼中使用其他地方的聲明:

(setf x 10) 

這似乎做工精細,並x似乎不像一個詞彙變量。它實際上是一個動態的全球化,就像我使用defparameter或defvar一樣,還是完全是其他的東西?

回答

6

實際上它在ANSI Common Lisp標準中沒有指定。

通常我更喜歡任何CL實現來設置動態綁定值或全局值。它不應該做任何事情。默認情況下,CMUCL似乎認爲當時宣佈符號是一個好主意。但這是一個壞主意,因爲沒有明顯的辦法擺脫全球特別宣言。

所以,一般我希望這樣的事情(在這裏,LispWorks):

CL-USER 66 > (defun foo() (setf x44 10)) 
FOO 

全局變量仍是未綁定:

CL-USER 67 > x44 

Error: The variable X44 is unbound. 
    1 (continue) Try evaluating X44 again. 
    2 Specify a value to use this time instead of evaluating X44. 
    3 Specify a value to set X44 to. 
    4 (abort) Return to level 0. 
    5 Return to top loop level 0. 

Type :b for backtrace or :c <option number> to proceed. 
Type :bug-form "<subject>" for a bug report template or :? for other options. 

CL-USER 68 : 1 > :top 

讓我們來調用該函數:

CL-USER 69 > (foo) 
10 

現在它具有全球價值:

CL-USER 70 > x44 
10 

但該變量未被聲明爲特殊的(因爲它將由DEFVARDEFPARAMETER)。這裏建立了一個詞彙綁定。

CL-USER 71 > (let ((x44 20)) (foo) x44) 
20 

當我們聲明中的局部變量是特殊的,那麼我們的函數更改綁定:

CL-USER 72 > (let ((x44 20)) (declare (special x44)) (foo) x44) 
10 
+1

謝謝!你的回答非常有幫助。在REPL中使用你的答案和一些測試,最終幫助我充分理解了我原來的陳述會發生的行爲。現在我也知道特殊和非特殊變量之間的區別。 – Gearov

2

很快,你能想到的setq,這是setf擴大你已經觀察到的,因爲這樣做只有一半的是什麼defvardefparameter做:

考慮到defparameter做到這一點:

(declaim (special x)) 
(setq x 10) 

Ie它向編譯器提供了一些元數據(關於x是什麼類型的數據)(在這種情況下,它告訴它它是一個「特殊」變量)並賦值。

特別是,defvar不會像這樣行事,如果它是頂級形式的話。該標準的行爲是初始化符號的價值細胞只有一次,所以它的代碼將更加複雜的東西,你能想到的是:提供的編譯器

(unless (boundp x) ; This is not entirely correct, because if the symbol 
         ; is otherwise known to the environment, but is unbound 
         ; defvar will not re-bind it, but I can't think of a way 
         ; to mimic that behavior 
    (declaim (special x)) 
    (setq x 10)) 

的元數據可能會或可能對代碼的行爲方式沒有任何影響。一般來說,元數據應該有助於編譯器更好地判斷代碼背後的意圖,從而可能導致優化。但它也可以用於文檔或調試。

您可以在Hyperspec中閱讀specialdeclare

0

據我所知,你應該避免使用setf(擴展到setq)和未聲明的變量。這些行爲可能會因實現而有所不同,即使您在REPL中的代碼運行良好,編譯後的程序可能會在意外的位置被竊聽。如果你這樣做,你可以在clisp中看到警告:

>(defun internal-setf() (setf some-var 10)) 
>(compile 'internal-setf) 
WARNING: in INTERNAL-SETF : SOME-VAR is neither declared nor bound, 
    it will be treated as if it were declared SPECIAL. 
相關問題