在LISP中使用defmacro时出现未绑定的变量错误

时间:2017-03-28 12:26:52

标签: lisp common-lisp clisp

我正在尝试在LISP中使用两种形式的宏,它会评估两种形式,但总是返回表单2的结果。下面是我正在使用的代码 -

(defmacro testmac (x body) (prog2 x body))

使用以下表格执行宏时,它正常工作并始终返回5,这是第二种形式。

(testmac (- 10 6) (/ 10 2))

但是当我尝试使用以下表单执行宏时,它的返回错误。

(testmac (print a) (print b)) 

以下是我得到的错误 -

debugger invoked on a UNBOUND-VARIABLE: The variable B is unbound.
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-INT:SIMPLE-EVAL-IN-LEXENV B #<NULL-LEXENV>)

为什么我收到此错误,如何使用宏来实现此功能?

P.S。我不能使用defun需要使用宏来执行(testmac(print a)(print b))

2 个答案:

答案 0 :(得分:5)

  

我正在尝试在LISP中使用带有两种形式的宏,它会对两种形式进行计算,但总是返回表单2的结果。

这通常不是一个好主意 - 尽管它可能只是不准确的措辞。宏不应该评估代码 - 不是没有充分理由。通常宏只是转换代码。然后,生成的代码决定要评估的内容。

(defmacro testmac (x body) (prog2 x body))

(testmac (- 10 6) (/ 10 2))

所以x是列表(- 10 6),正文是列表(/ 10 2)

你的宏返回第二个列表。

CL-USER 11 > (macroexpand-1 '(testmac (print a) (print b)))
(PRINT B)

宏返回表单(print b)。然后它会被执行。

CL-USER 12 > (testmac (print a) (print b))

Error: The variable B is unbound.

如果B未定义,则会收到您看到的错误。

没有魔法。

答案 1 :(得分:3)

这是因为您的testmac宏直接执行(prog2 x body),而不是扩展到它。

你需要这样写:

(defmacro testmac (x body)
  `(prog2 ,x ,body))

反引号后的表格不会被评估,但是逗号之后的表格会被评估。

你可以(你应该!)测试这样的扩展:

(macroexpand-1 '(testmac (print 42) (print 51)))

给出了:

(PROG2 (PRINT 42) (PRINT 51))
相关问题