为什么Clojure在AOT编译期间评估表单?

时间:2016-07-27 16:08:15

标签: clojure compilation

我已经设置了小项目:

project.clj

(defproject testing-compilation "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.8.0"]]

  ;; this is important!
  :aot :all)

的src / core.clj

(ns testing-compilation.core)

(def x (do
         (println "Print during compilation?")
         1))

然后当我在项目目录中lein compile时,我看到了打印输出:

$ lein compile
Compiling testing-compilation.core
Print during compilation?

我的问题是:为什么clojure在AOT编译期间评估顶级表单?它们不应该在程序启动时进行评估吗?

供参考,Common Lisp默认情况下不评估表单provides ability to tune this behaviour。 Clojure中有类似的东西吗?如果没有,Clojure文档是否明确说明了这种行为?

UPD:表单也会在启动时进行评估。

在指定主命名空间并编写打印Hello, world!的主函数后,我这样做了:

$ lein uberjar
Compiling testing-compilation.core
Print during compilation?
Created testing-compilation-0.1.0-SNAPSHOT.jar
Created testing-compilation-0.1.0-SNAPSHOT-standalone.jar

$ java -jar target/testing-compilation-0.1.0-SNAPSHOT-standalone.jar
Print during compilation?
Hello world!

1 个答案:

答案 0 :(得分:6)

AOT流程的第一部分是找到包含主命名空间的文件,并从上到下按evaluating每个表达式加载它。

这些表达式中的一些将是require表达式,它们将加载其他名称空间,从而递归加载更多名称空间。

其他将是defn表达式,它们将启动编译器并生成类文件。生成一个类文件for each function

其他表达式可能会进行一些计算,然后执行生成类文件的操作,因此让它们有机会运行是很重要的。这是一个简单的例子:

user> (let [precomputed-value (reduce + (range 5))]
        (defn funfunfun [x]
          (+ x precomputed-value)))
#'user/funfunfun
user> (funfunfun 4)
14

可以设计一个不会在开始时评估顶级表单的lisp,或者如您所述,将其设置为可选。在Clojure的情况下,决定在AOT和“非AOT”加载中保持单一的评估策略,因此程序总是运行相同,无论它们如何编译。这些是他人做出的个人设计选择,所以我不能在这里说出他们的动机。