为什么在修改它时需要重新编译使用Common Lisp宏的定义?

时间:2013-06-07 10:20:18

标签: macros lisp common-lisp

这是一个让我很好奇的怀疑。

为什么在修改它时还需要重新编译使用Common Lisp宏的定义(显然,重新编译修改后的Common Lisp宏)?

提前致谢。

3 个答案:

答案 0 :(得分:11)

Common Lisp宏是代码替换,它们发生在“宏扩展时”。对于解释代码,此可能为“运行时”。对于已编译的代码,它几乎总是在“编译时”。

代码被替换后,在生成的编译代码中没有对宏的引用(如果宏用法已保存到文件中,则磁盘上的原始源仍具有此功能)。

虽然在lisp系统中会有一些方便,它保存了所有“预宏扩展”功能体,并跟踪在哪里使用了哪些宏并自动重新编译使用给定宏的任何内容(可能是递归的),这被排除在标准之外。

通常情况下,我在开发的早期编写我的实用程序宏,所以对我来说没有太多需要拥有这个功能而且我没有它比我更喜欢它(它减少了运行)图像大小相当多,不需要跟踪所有这些)。

答案 1 :(得分:9)

请注意可能是必要的。

原因是编译实现中的宏在编译时只展开一次,而宏本身在生成的代码中不存在。

更清楚地考虑

(defmacro badsquare (x)
  `(* ,x ,x))

(defun f (x)
  (badsquare (+ x 3))

当编译器分析f代码时会将其扩展为

(defun f (x)
  (* (+ x 3) (+ x 3)))

并且badsquare宏的引用不一定存在,如果您将badsquare宏重新定义为其他内容,这对f没有任何影响,除非您还重新编译它

答案 2 :(得分:3)

仅在以下情况下重新编译已更改的宏的用法:

  • 旧宏有一个错误。宏存在错误意味着它会产生错误的代码。坏代码必须由固定宏重新生成。

  • 旧的宏生成了糟糕的代码。我们希望使用生成最好代码的最新最好的宏重新编译代码。

  • 旧宏的运行时支持将消失。旧宏生成的代码调用特殊的运行时支持函数,这些函数也由包提供。其中一些功能在新版本的宏包中消失,或者以向后不兼容的方式发生变化。因此,当安装新函数时,现有的编译代码将无法正常工作。 Corrolary:在维护具有运行时支持的宏包时,请记住可能无法重新编译的代码,并制定维护兼容性和强制淘汰的计划。

  • <强>一致性即可。您已经多次修改了多个宏,但是您根据宏重新编译了一些函数或源文件,而忽略了其他宏。因此,您正在测试一个“弗兰肯斯坦的怪物”图像,其中包含无法再从源代码重建的宏扩展。您正在进行的任何测试仅对该图像有效。当事情破裂时,可能只是因为不一致,所以你浪费时间追逐不存在的错误。反之亦然:有些东西是正确的,但仅仅是由于陈旧和新鲜代码的结合。您希望从头开始重建所有内容,以便为测试软件或打包版本提供明确定义的基准。

  • 界面更改。宏的语法已更改,因此必须更新代码才能使用新宏。虽然可以继续使用旧宏扩展的旧二进制代码,但是您可能会运行与更新的源代码相关的二进制文件(使我们回到之前的一致性点) )。

如果这些条件都不适用,那么我们可以让自己在重新编译依赖于宏的代码时变得懒惰。