clojure如何在编译时评估代码?

时间:2017-11-02 19:00:35

标签: clojure macros

这是我写的两个宏

(defmacro hello [x] '(+ 1 2))

&安培;

(defmacro hello [x] (eval '(+ 1 2)))

在宏扩展第一个时,我得到(+ 1 2),而宏扩展第二个,我得到值3.这是否意味着在编译时添加了?这怎么可能呢?如果不是'(+ 1 2)我编写了一个查询数据库的函数,该怎么办?它会在编译时查询db吗?

2 个答案:

答案 0 :(得分:7)

宏将任意代码注入编译器。通常,目的是"预处理"像(1 + 2)这样的自定义代码包含在Clojure理解的内容中,如(+ 1 2)。但是,如果您真的想要,可以将 任何 (包括数据库访问)包括在编译阶段。毕竟编译器只是在通用计算机上运行的一个软件。由于它是开源的,您可以直接修改编译器代码来执行任何操作。

使用宏只是修改/扩展基本编译器代码的一种更方便的方法,它是为扩展核心Clojure语言而优化的。但是,宏不仅限于那个用例(如果你真的想变得疯狂)。

使用C ++表达式模板机制有类似的能力,它是图灵完整的编译器预处理器。一个着名的例子是使用编译器计算前几个素数作为"错误"消息。见http://aszt.inf.elte.hu/~gsd/halado_cpp/ch06s04.html#Static-metaprogramming

答案 1 :(得分:2)

宏体在编译期间执行,其返回值用于替换代码中的用法,这个新代码将被编译。

因此你的宏代码:

(defmacro hello [x] (eval '(+ 1 2)))

在编译期间,

实际上将以eval形式执行'(+ 1 2),并且该表达式的结果值(3)将作为宏替换其用法的结果返回(例如{ {1}})。