2013-07-28 31 views
2

我是新來的Lisp和由保羅·格雷厄姆和一個演習通過ANSI Common Lisp的會是這樣定義適用,如果任何號碼打印出來它會返回默認情況下,八進制打印之前的功能。爲什麼ANSI Common Lisp的範圍示例不能按預期工作?

我試過如下:

(let ((*print-base* 8)) 
    (defun like-apply (&rest args) 
    (apply #'apply args))) 

但預期它沒有工作:

(like-apply #'princ '(8)); returns 8 8 (expecting 10 8) 

以下工作不過:

(defun apply8 (&rest args) 
    (let ((*print-base* 8)) 
    (apply #'apply args))) 

返回正確:

(apply8 #'princ '(8)); returns 10 8 (as expected) 

所以我的問題是爲什麼第二個例子工作,但不是第一個?這兩個似乎操縱*print-base*變量。

回答

6

Common Lisp使用let來綁定詞法和「特殊」(動態)變量。你期望的行爲是詞彙,你觀察到的行爲是動態的。打印機變量都是特殊的,所以讓我們爲它們創建一個動態綁定。

打印機變量有時用在爲什麼動態綁定可能有用的示例中。例如,您可以通過綁定* print-base *來控制princ的行爲的事實是通過動態綁定來啓用的,否則在princ被定義時,princ會引用* print-base * active的綁定。

此行爲是許多Common Lisp程序員堅持使用特殊變量的* earmuffs *命名約定的主要原因。請注意,defvar和defparameter都會創建特殊變量。

+1

感謝您解釋如此清楚,以及關於defparameter和defvar創建特殊變量的附加提示。當他們現在特殊時,它意味着什麼是完全有意義的。 – ajivani

4

您觀察到的行爲是正確的。

這將是有益的比較

(let ((*print-base* 8)) 
    (defun f1() 
    *print-base*)) 

(defun f2() 
    (let ((*print-base* 8)) 
    *print-base*)) 

發現,(f1)返回10(f2)回報8

這是因爲*print-base*圍繞的f1定義的制約,所以它是8f1定義但不是當它被執行

+1

我想我明白了,因爲它是一個特殊的變量(從上面的m-n的回答),它具有動態範圍。這意味着在第一個示例中,它返回到* print-base *所具有的全局默認值(如果沒有更改,則爲10)。在第二個示例中,每次調用f2時它都會更改* print-base *的值。感謝你們兩位。 – ajivani

相關問題