Macro calling a function works in interpreter, fails in compiler (SBCL + CMUCL)

天涯浪子 提交于 2019-12-10 22:53:23

问题


As suggested in a macro-related question I recently posted to SO, I coded a macro called "fast" via a call to a function (here is the standalone code in pastebin):

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

This works in the REPL, under both SBCL and CMUCL:

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

$

Unfortunately, however, the code no longer compiles:

$ 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.

So it seems that by having my macro "fast" call functions ("clone","operation-p") at compile-time, I trigger issues in Lisp compilers (verified in both CMUCL and SBCL).

Any ideas on what I am doing wrong and/or how to fix this?


回答1:


Some remarks about your code.

  • multiple tests of an object for equality can be replaced by MEMBER

  • backquote with a following comma does nothing. You can just remove that.

  • you can ensure that your functions are available for a macro by a) moving these functions to an additional file and compile/load that before use of the macro, by b) using EVAL-WHENto inform the compiler to evaluate the definition of the functions or by c) adding the functions to the macro as local functions

Example:

(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))))

Note that this and your version of FAST are not complete code walkers. They recognize only simple function calls (and not the other Lisp constructs like LAMBDA, LET, FLET, LABELS, etc.).




回答2:


Never mind, I figured it out: I had to move the functions invoked by the macro (and therefore required during compilation) in a separate file, "compile-file" it first, "load" it, then "compile-file" the one with the macro.




回答3:


Macro-expansion tie happens (typically) during compile time.

That means that any functions used during the macro expansion (note, not necessarily in the macro-expansion, the return value as it were) must be defined when the macro is encountered during compilation.



来源:https://stackoverflow.com/questions/8138714/macro-calling-a-function-works-in-interpreter-fails-in-compiler-sbcl-cmucl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!