Mad*_*ist 3 lisp macros common-lisp lexical-scope
我目前正在通过Graham的On Lisp工作,发现这一点很难理解:
绑定.词汇变量必须直接出现在源代码中.
setq
例如,没有计算第一个参数,所以任何构建的都setq
必须是一个扩展为a的宏setq
,而不是一个调用它的函数.同样对于运算符,例如let
,其参数在lambda表达式中作为参数出现,对于像扩展为let
s的宏这样的运算,依此类推.任何要更改其参数的词法绑定的新运算符都必须写为宏.
这来自第8章,其中描述了何时应该和不应该使用宏来代替函数.
他在这一段中究竟是什么意思?有人会给出一两个具体的例子吗?
非常感激!
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
更新变量what
是20
,但它是具有价值的局部变量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)
一个类似的例子.你无法模仿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)
Run Code Online (Sandbox Code Playgroud)
无论你传递什么参数,你都会得到一个总是调用递归情况的无限循环,因为所有的my-if
参数总是被评估.随着cond
和if
的test
获取评估,并基于该要么then
或else
评估,但从来都无条件地.