2013-07-28 30 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

相关问题