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

Ole*_*Cat 3 compilation clojure

我已经建立了小项目:

project.clj:

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

  ;; this is important!
  :aot :all)
Run Code Online (Sandbox Code Playgroud)

SRC/core.clj

(ns testing-compilation.core)

(def x (do
         (println "Print during compilation?")
         1))
Run Code Online (Sandbox Code Playgroud)

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

$ lein compile
Compiling testing-compilation.core
Print during compilation?
Run Code Online (Sandbox Code Playgroud)

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

作为参考,Common Lisp默认不评估表单,并提供调整此行为的功能.Clojure中有类似的东西吗?如果没有,Clojure文档是否明确说明了这种行为?

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

指定主命名空间并编写打印的main函数后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!
Run Code Online (Sandbox Code Playgroud)

Art*_*ldt 6

AOT过程的第一部分是找到包含主命名空间的文件,并通过从上到下评估每个表达式来加载它.

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

其他将是defn具有启动编译器和生成类文件的效果的表达式.为每个函数生成一个类文件.

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

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

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