Common Lisp宏中的词法绑定

Mad*_*ist 3 lisp macros common-lisp lexical-scope

我目前正在通过Graham的On Lisp工作,发现这一点很难理解:

绑定.词汇变量必须直接出现在源代码中.setq例如,没有计算第一个参数,所以任何构建的都setq必须是一个扩展为a的宏setq,而不是一个调用它的函数.同样对于运算符,例如let,其参数在lambda表达式中作为参数出现,对于像扩展为lets的宏这样的运算,依此类推.任何要更改其参数的词法绑定的新运算符都必须写为宏.

这来自第8章,其中描述了何时应该和不应该使用宏来代替函数.

他在这一段中究竟是什么意思?有人会给出一两个具体的例子吗?

非常感激!

Syl*_*ter 7

setq是一种特殊形式,不评估其第一个参数.因此,如果你想制作一个更新某些东西的宏,你就不能这样做:

(defun update (what with)
  (setq what with))

(defparameter *test* 10)
(update *test* 20)        ; what does it do?
*test*                    ; ==> 10
Run Code Online (Sandbox Code Playgroud)

所以里面的功能update setq更新变量what20,但它是具有价值的局部变量10即得到更新,而不是*test*自己.为了更新*test* setq必须具有*test*第一个参数.宏可以这样做:

(defmacro update (what with)
  `(setq ,what ,with))

(update *test* 20)        ; what does it do?
*test*                    ; ==> 20
Run Code Online (Sandbox Code Playgroud)

您可以从宏扩展中看到确切的结果代码:

(macroexpand-1 '(update *test* 20))
; ==> (setq *test* 20) ; t
Run Code Online (Sandbox Code Playgroud)

一个类似的例子.你无法模仿ifcond使用功能:

(defun my-if (test then else)
  (cond (test then)
        (t else)))

(defun fib (n)
  (my-if (< 2 n) 
         n
         (+ (fib (- n 1)) (fib (- n 2)))))

(fib 3)
Run Code Online (Sandbox Code Playgroud)

无论你传递什么参数,你都会得到一个总是调用递归情况的无限循环,因为所有的my-if参数总是被评估.随着condiftest获取评估,并基于该要么thenelse评估,但从来都无条件地.