好的,我很清楚如何同时使用函数和宏。
我很好奇的是,为什么编译器在集成两者时不能更聪明一些,例如:考虑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
是的,我知道我可以通过取出“apply”来完成这项工作 - 但为什么编译器无法弄清楚如何自己做这个呢?
在Clojure /其他LISP中是否可以创建一个apply或其他更高阶函数的版本,这些函数同时兼容函数和宏作为参数?
答案 0 :(得分:11)
这个答案不是关于Clojure,而是一般的Lisp和宏。
记住:
APPLY可以使用在运行时创建的参数列表调用函数。
宏可以从一些源代码生成新的源代码 - 生成的源代码将运行。
现在:
如果允许apply在运行时将不同的源代码提供给宏,则需要能够在运行时生成结果代码并执行生成的代码。
因此,在编译的Lisp系统中,每次使用宏调用APPLY都可能会创建需要在运行时编译的新代码,以便能够执行它。这也意味着当您的代码执行并且代码有问题时,您可能会在运行时获得新的编译器错误。因此,要在运行时应用宏,您需要一个编译器和所有必要的信息(例如其他宏)才能扩展和编译代码。
这也意味着在一般情况下你不能在运行时之前用宏编译APPLY,因为不知道要应用的运行时参数是什么。
在基于解释器的Lisp中,可能会有更多的信息和宏可以一直应用。
在早期的Lisp中,有正常的功能和所谓的FEXPR。 FEXPR允许灵活的调用和运行时代码操作。在Lisp的历史后期,它们已被宏替换,因为宏允许高效编译,并且在基于编译器的系统中,允许在运行时之前处理语法错误。
答案 1 :(得分:2)
您所描述的内容听起来像是一流的宏(即:您可以像函数一样操作的宏)。有些lisps有这些(例如Arc),但apply
由于不是宏本身,可能仍然无效。