调用函数的宏在解释器中工作,在编译器中失败(SBCL + CMUCL)

时间:2011-11-15 15:24:50

标签: macros lisp common-lisp

根据a macro-related question I recently posted to SO的建议,我通过调用函数(here is the standalone code in pastebin)编写了一个名为“fast”的宏:

(defun main ()
  (progn
    (format t "~A~%" (+ 1 2 (* 3 4) (+ 5 (- 8 6))))
    (format t "~A~%" (fast (+ 1 2 (* 3 4) (+ 5 (- 8 6)))))))

这适用于REPL,在SBCL和CMUCL下:

$ sbcl
This is SBCL 1.0.52, an implementation of ANSI Common Lisp.
...
* (load "bug.cl")
22
22

$

不幸的是,代码不再编译:

$ sbcl
This is SBCL 1.0.52, an implementation of ANSI Common Lisp.
...
* (compile-file "bug.cl")
...
;   during macroexpansion of (FAST (+ 1 2 ...)). Use *BREAK-ON-SIGNALS* to
;   intercept:
;
;    The function COMMON-LISP-USER::CLONE is undefined.

所以看起来通过在编译时让我的宏“快速”调用函数(“clone”,“operation-p”),我在Lisp编译器中触发了问题(在CMUCL和SBCL中验证)。

关于我做错了什么和/或如何解决这个问题的任何想法?

3 个答案:

答案 0 :(得分:4)

关于您的代码的一些评论。

  • 对象的多次测试可以用MEMBER

  • 替换。
  • 使用以下逗号的反引号不执行任何操作。你可以删除它。

  • 您可以通过以下方式确保您的函数可用于宏:a)将这些函数移动到其他文件并在使用宏之前编译/加载,b)使用EVAL-WHEN通知编译器来评估函数的定义或c)将函数作为本地函数添加到宏

示例:

(defmacro fast (&rest sexpr)
  (labels ((operation-p (x)
             (member x '(+ - * /)))
           (clone (sexpr)
             (if (consp sexpr)
                 (destructuring-bind (head . tail) sexpr
                   (if (operation-p head)
                       `(the fixnum (,head ,@(clone tail)))
                     (cons (clone head) (clone tail))))
               sexpr)))
    (car (clone sexpr))))

请注意,此版本和FAST版本不是完整的代码助手。它们只识别简单的函数调用(而不是其他Lisp构造,如LAMBDA,LET,FLET,LABELS等)。

答案 1 :(得分:2)

没关系,我想通了:我必须将宏调用的函数(因此在编译期间需要)移动到一个单独的文件中,首先“编译文件”,“加载”它,然后“编译 - 文件“与宏的那个。

答案 2 :(得分:1)

在编译期间(通常)发生宏扩​​展绑定。

这意味着在宏扩展期间使用的任何函数(注意,不一定 in 宏扩展,返回值都是如此)必须在编译期间遇到宏时定义。 / p>