【问题标题】:Compilation and Macros编译和宏
【发布时间】:2017-06-10 09:47:30
【问题描述】:

这是关于“编译和宏扩展”主题的引用,来自Common Lisp: A gentle introduction to symbolic computation一书。

(defmacro bad-announce-macro ()
(format t "~%Hi mom!"))
(defun say-hi ()
(bad-announce-macro))
> (compile 'say-hi)
Hi, mom!
SAY-HI
> (say-hi)
NIL

在上面的例子中,宏被扩展为过程的一部分 编译SAY-HI。所以编译器说‘‘Hi, mom!’’的结果 宏是 NIL,所以这就是编译到 SAY-HI 主体中的内容。什么时候 我们调用编译后的SAY-HI 函数,它什么也没说,因为宏有 被它的扩展所取代。


在这句话中,作者说

宏已被其扩展替换

好的,所以它不应该至少显示打印的 "Hi mom!" 吗?因为虽然宏没有返回任何东西,但它仍然被某些东西取代(它是扩展)。根据代码,我假设
当一个函数在编译后被调用时,在它的主体中调用的所有宏都被扩展为 它们返回的结果 ,而不是它们自己的主体中的任何内容。

我不确定这是否正确。而这样做的原因也不清楚。

【问题讨论】:

  • 宏的展开就是宏的返回值。由于宏返回NIL,它的扩展是NIL,这就是它在SAY-HI函数中的替换。
  • @jkiiski : 但是为什么函数打印"Hi mom!"直到它没有被编译?
  • 宏在编译代码时被展开(宏的副作用发生在展开过程中)。在此之前,无论您使用什么实现,它都是解释代码(并且在调用函数时宏会动态扩展)。
  • 所以,无论何时展开宏,我都会看到它的副作用。并且在编译的情况下只展开一次,之后的每次调用都会使用宏的结果。而在解释代码的情况下,每次调用时都会对其进行扩展。对吗?
  • 是的,没错。

标签: compilation macros common-lisp


【解决方案1】:

未指定宏的扩展频率。

在 LispWorks 中解释 Lisp:

CL-USER 49 > (say-hi)

Hi mom!
Hi mom!
NIL

此处的宏扩展在运行时进行了两次。

在编译后的代码中,我们期望在运行时不需要宏扩展。因此,在您的示例中,不会打印任何内容,因为您生成的代码什么都不做:

CL-USER 50 > (compile 'say-hi)

Hi mom!
SAY-HI
NIL
NIL

CL-USER 51 > (say-hi)
NIL

宏扩展为NIL

CL-USER 52 > (macroexpand '(bad-announce-macro))

Hi mom!
NIL        ; <- the macro expansion
T

【讨论】:

    猜你喜欢
    • 2016-02-16
    • 1970-01-01
    • 2011-08-21
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    • 2018-10-26
    相关资源
    最近更新 更多