Common Lisp宏中的词法绑定

5

我目前正在阅读格雷厄姆的《On Lisp》,但有一段内容比较难理解:

绑定。词法变量必须直接出现在源代码中。例如,setq的第一个参数不会被计算,因此任何基于setq构建的内容必须是一个扩展为setq的宏,而不是调用setq的函数。同样,对于像let这样的运算符,其参数应出现为lambda表达式的参数,在像do这样将展开为let的宏中等等。任何要改变其参数的词法绑定的新操作符都必须编写为宏。

这段话来自第8章,描述了什么时候应该使用宏代替函数。

他在这段话中到底想说什么?有没有人能给出一个或两个具体的例子?

非常感谢!


1
作为一名有经验的Lisper,我完全理解那段文字试图表达的意思,只是我无法解析实际的文本。如果我用手指沿着段落中间滑动,并在0.5秒内快速浏览它,那么它就有意义,但如果我挑选单个单词和短语,那么它就有点难以理解。 - Kaz
1
“let” 的“arguments”不会出现在 lambda 表达式中。这是什么意思? - Kaz
你是在说这段话写得很糟糕吗?这个段落就是一个例子,无论我读了多少遍,我仍然会问自己,“什么鬼?” - MadPhysicist
1个回答

8

setq是一种特殊形式,不会计算其第一个参数。因此,如果你想创建一个更新某些内容的宏,不能这样做:

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

(defparameter *test* 10)
(update *test* 20)        ; what does it do?
*test*                    ; ==> 10

update函数内部,setq将变量what更新为20,但它是一个局部变量,其值为10,被更新的是该变量而不是*test*本身。为了更新*test*setq必须将*test*作为第一个参数。宏可以做到这一点:

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

(update *test* 20)        ; what does it do?
*test*                    ; ==> 20

您可以准确地看到宏展开的结果代码:
(macroexpand-1 '(update *test* 20))
; ==> (setq *test* 20) ; t

一个类似的例子。你无法使用一个函数来模仿if的功能,也不能用cond代替:

(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)

无论您传递什么参数,都会得到一个无限循环,因为所有的“my-if”参数都被始终计算。使用“cond”和“if”,“test”将被评估,并根据其评估结果评估“then”或“else”,但从不无条件地评估它们。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接