我已经设置了小项目:
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!
答案 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”加载中保持单一的评估策略,因此程序总是运行相同,无论它们如何编译。这些是他人做出的个人设计选择,所以我不能在这里说出他们的动机。