是否可以在运行时在已编译的Lisp可执行文件中扩展宏?我希望这是不可能的,因为宏扩展只能在预编译时进行,但是当我在已编译的代码中调用macroexpand时,我会得到输出。
答案 0 :(得分:4)
在Lisp中,术语“运行时”和“编译时”是指正在处理特定代码段的情况,而不是某些静态语言中的绝对代码。如果我们评估(compile nil '(lambda ()))
,这是compile
函数的运行时,但是lambda
表单的编译时:这两个时间是同时发生的。
在所有情况下都可以使用整个语言。当您构建一个独立的可执行文件时,该映像不仅包含对扩展宏的支持,而且还包含对代码进行编译的支持。您的Lisp应用程序可以调用compile-file
将Lisp源代码编译为对象形式,并调用load
来加载生成的对象代码。
从Lisp应用程序映像中删除垃圾和未使用的功能以使其更小的过程称为"tree shaking"。如果您不希望在应用程序中使用编译器或宏扩展器,请查看是否/如何通过实现的摇晃树技术将其删除。
答案 1 :(得分:3)
宏是通常在编译或评估过程中自动调用的函数,然后将其返回值代替原始表达式进行编译或评估。
但是,由于它只是一个函数,因此也没有阻止它在运行时显式调用的功能,这就是MACROEXPAND
和MACROEXPAND-1
的作用。
大致相当于:
(defun macroexpand-1 (form &optional env)
(if (and (listp form) (car form)) ;; list expression
(let ((macfun (macro-function (car form)))
(if macfun
(funcall macfun form env)
form))
form))
(请注意,此定义不处理符号宏或使用*MACROEXPAND-HOOK*
来保持简单。)
在定义宏时可以使用EVAL-WHEN
,以使宏定义仅在编译环境中可用。如果这样做,在运行时尝试扩展将失败。