使用逗号和反引号的正确组合消除宏中的eval

时间:2015-05-01 10:05:27

标签: macros common-lisp eval

我已经写了一个按预期工作的宏。问题是它包含eval。我想摆脱它,但尽可能地尝试,我无法找到正确的反引号和逗号组合。

(defmacro mymacro (x &body body)
  `(myothermacro ,(fun1 (eval x))
     ,@body))

此处myothermacro是一个宏,fun1是一个函数。

这是理想的行为:

(defvar v 88)

(defun fun1 (z) (1+ z))

(defmacro mymacro (x &body body)
  `(myothermacro ,(fun1 (eval x))
     ,@body))

(macroexpand-1 '(mymacro v 42 43 44)) 

    => (MYOTHERMACRO 89 42 43 44)

2 个答案:

答案 0 :(得分:3)

没有任何可以帮助你的反引号。在一个场景中,你有一个以上的反引号,同样多的quasiquote,因此你可以获得不同的引用数据层,但不能多次评估数据。

了解宏不会执行任何运行时非常重要。因此,如果您要使用宏(mymacro variable (my-function x)),宏函数mymacro会立即被提供variable(my-function x),并且结果会被放置到位。 variable可能尚不存在,因此评估它为时过早。当您定义使用宏的函数时,它很可能会在存储函数之前扩展宏。在运行时没有宏,因为它们都被扩展了,但是如果传递给宏的参数和它的扩展实际上根据词法环境和全局绑定有意义,这是第一次可以得出结论。

也许如果您添加了更多信息,那么就有办法帮助您解决实际问题,因为我觉得这是XY problem

答案 1 :(得分:0)

如果我的想法正确,您需要使用阅读时间评估。 像这样:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defparameter *foo* "foo"))

(defmacro bar (arg)
  `(list #.*foo* ,arg))

CL-USER> (macroexpand '(bar "bar"))
         (LIST "foo" "bar")

对于defconstant而不是defparameter你可能会更好,因为它更清楚意图。