我知道當你想在Lisp中進行動態/全局綁定時,可以使用defparameter或defvar。我也知道你可以使用defun參數列表或let語句來製作詞彙綁定,幾乎無處不在。當我在LISP中使用簡單的setf語句時會發生什麼?
什麼我不知道是它到底是什麼我做當我提出這樣的,其中x未聲明或代碼中使用其他地方的聲明:
(setf x 10)
這似乎做工精細,並x似乎不像一個詞彙變量。它實際上是一個動態的全球化,就像我使用defparameter或defvar一樣,還是完全是其他的東西?
我知道當你想在Lisp中進行動態/全局綁定時,可以使用defparameter或defvar。我也知道你可以使用defun參數列表或let語句來製作詞彙綁定,幾乎無處不在。當我在LISP中使用簡單的setf語句時會發生什麼?
什麼我不知道是它到底是什麼我做當我提出這樣的,其中x未聲明或代碼中使用其他地方的聲明:
(setf x 10)
這似乎做工精細,並x似乎不像一個詞彙變量。它實際上是一個動態的全球化,就像我使用defparameter或defvar一樣,還是完全是其他的東西?
實際上它在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
但該變量未被聲明爲特殊的(因爲它將由DEFVAR
或DEFPARAMETER
)。這裏建立了一個詞彙綁定。
CL-USER 71 > (let ((x44 20)) (foo) x44)
20
當我們聲明中的局部變量是特殊的,那麼我們的函數更改綁定:
CL-USER 72 > (let ((x44 20)) (declare (special x44)) (foo) x44)
10
很快,你能想到的setq
,這是setf
擴大你已經觀察到的,因爲這樣做只有一半的是什麼defvar
或defparameter
做:
考慮到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))
的元數據可能會或可能對代碼的行爲方式沒有任何影響。一般來說,元數據應該有助於編譯器更好地判斷代碼背後的意圖,從而可能導致優化。但它也可以用於文檔或調試。
據我所知,你應該避免使用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.
謝謝!你的回答非常有幫助。在REPL中使用你的答案和一些測試,最終幫助我充分理解了我原來的陳述會發生的行爲。現在我也知道特殊和非特殊變量之間的區別。 – Gearov