Common Lisp 宏中的词法绑定
Lexical Bindings in Common Lisp Macros
我目前正在研究 Graham 的 On Lisp,发现这个特别的部分很难理解:
Binding. Lexical variables must appear directly in the source code. The
first argument to setq
is not evaluated, for example, so anything
built on setq
must be a macro which expands into a setq
, rather than a
function which calls it. Likewise for operators like let
, whose
arguments are to appear as parameters in a lambda expression, for
macros like do which expand into let
s, and so on. Any new operator
which is to alter the lexical bindings of its arguments must be
written as a macro.
这来自第 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
被评估,但从来没有无条件地。
我目前正在研究 Graham 的 On Lisp,发现这个特别的部分很难理解:
Binding. Lexical variables must appear directly in the source code. The first argument to
setq
is not evaluated, for example, so anything built onsetq
must be a macro which expands into asetq
, rather than a function which calls it. Likewise for operators likelet
, whose arguments are to appear as parameters in a lambda expression, for macros like do which expand intolet
s, and so on. Any new operator which is to alter the lexical bindings of its arguments must be written as a macro.
这来自第 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
被评估,但从来没有无条件地。