(defun make-it-5 (num)
(setq num 5))
(setq a 0)
(make-it-5 a)
;; now a is still 0, not 5.
在上面的代码中,似乎既没有(setq a 5)也没有(setq 0 5)。如果(setq a 5)发生,则a将更改为5,但a仍为0.如果(setq 0 5)发生,则会发生Lisp错误。怎么了?这是我的问题。
对于一些通过谷歌搜索来到这里的人并想知道如何使make-it-5正如其名称所示,其中一种方法是
(defmacro make-it-7 (num) ; defmacro instead of defun
`(setq ,num 7))
(setq a 0)
(make-it-7 a)
;; now a is 7.
另一个是:
(defun make-it-plus (num-var)
(set num-var (+ 1 (symbol-value num-var))) ; `set' instead of `setq'
)
(setq a 0)
(make-it-plus 'a) ; 'a instead of a
;; now a is 1.
答案 0 :(得分:7)
简短回答是(setq num 5)
changes the binding for num
,它是make-it-5
函数的本地绑定。
细分如下。确保您熟悉evaluation的概念是很好的。
当评估(make-it-5 a)
时,解释器在表达式的第一个元素中查找函数。在这种情况下,第一个元素是符号(make-it-5
- 这意味着它是named function),因此它在符号的function cell中查找。注意:此查找可以重复,请参阅Symbol Function Indirection。
评估表达式的其余元素以查找值。在这种情况下,只有一个符号(a
),因此解释器返回the contents of its value cell,即0
。
然后,解释器将该函数应用于参数列表,其中包括创建local bindings between its arguments to the values passed in。在这种情况下,会在符号num
和值0
之间生成local binding。然后在该环境中评估函数体。
正文只是一个表达式,是setq
的“召唤”。我在引号中加上“call”,因为setq
是special form并且没有评估它的第一个参数,但是查找符号并设置most local existing binding,这是在{}内创建的绑定函数make-it-5
。
因此,您正在更改函数num
的本地符号make-it-5
的绑定。