【问题标题】:Make macros and functions integrate more seamlessly使宏和函数的集成更加无缝
【发布时间】:2011-03-11 01:44:31
【问题描述】:

好的,我非常了解如何使用函数和宏。

我很好奇的是为什么编译器在集成两者时不能更聪明一点,例如考虑 Clojure 代码:

(defmacro wonky-add [a b] `(+ ~a (* 2 ~b)))

(defn wonky-increment [a] (apply wonky-add a 1))
=> Error: can't take value of a macro

是的,我知道我可以通过取出“应用”来完成这项工作 - 但为什么编译器自己无法弄清楚如何做到这一点?

是否有可能在 Clojure / 其他 LISP 中创建一个版本的 apply 或其他高阶函数,它们与函数和宏作为参数同样适用?

【问题讨论】:

    标签: compiler-construction functional-programming macros clojure lisp


    【解决方案1】:

    这个答案不是关于 Clojure,而是关于一般的 Lisp 和宏。

    记住:

    APPLY 是为了能够使用在运行时创建的参数列表调用函数。

    宏用于从一些源代码生成新的源代码 - 生成的源代码将运行。

    现在:

    如果您允许应用程序在运行时将不同的源代码提供给宏,则需要能够在运行时生成结果代码并执行生成的代码。

    因此,在已编译的 Lisp 系统中,每次使用宏调用 APPLY 都可能会创建需要在运行时编译才能执行的新代码。这也意味着当你的代码正在执行并且代码有一些问题时,你可能会在运行时遇到新的编译器错误。因此,要在运行时应用宏,您需要一个编译器和所有必要的信息(例如其他宏)才能扩展和编译代码。

    这也意味着在一般情况下,您不能在运行前使用宏编译 APPLY,因为不知道要应用的运行时参数是什么。

    在基于解释器的 Lisp 中,可能有更多的信息,并且可以一直应用宏。

    在早期的 Lisp 中有正常的函数和所谓的 FEXPR。 FEXPR 允许灵活的调用和运行时代码操作。在 Lisp 历史的后期,它们已被宏取代,因为宏允许高效编译,并且在基于编译器的系统中,允许在运行前处理语法错误。

    【讨论】:

      【解决方案2】:

      您所描述的内容听起来像是一流的宏(即:您可以像函数一样操作的宏)。一些 lisps 有这些(例如Arc),但apply 本身不是宏,可能仍然无法工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-13
        • 1970-01-01
        • 2010-11-26
        相关资源
        最近更新 更多