Clojure fn调用不会在编译时执行

Clojure fn调用不会在编译时执行,clojure,Clojure,我已在一个ns中定义了以下内容: 有一个服务原子和另一个要添加到该原子的函数- (ns ex.first) (def services (atom [])) (defn add-service [fns] (swap! services conj fns)) 在另一个ns中的代码中,我这样做- (ns ex.second ..) (add-service [fn1 fn2 fn3]) 1) 我假设,当我运行编译代码的repl时,它应该将向量添加到atom中。但是,当我评估@服务

我已在一个ns中定义了以下内容:

有一个服务原子和另一个要添加到该原子的函数-

(ns ex.first)

(def services (atom []))

(defn add-service
  [fns]
  (swap! services conj fns))
在另一个ns中的代码中,我这样做-

(ns ex.second ..)

(add-service [fn1 fn2 fn3])
1) 我假设,当我运行编译代码的repl时,它应该将向量添加到atom中。但是,当我评估
@服务时,它返回
[]

2) 如果我在repl中评估
(添加服务[fn1 fn2 fn3])
,上述方法就可以起作用

3) 我还尝试将
addservice
fn转换为宏。然而,我仍然发现
@services
是空的

因此,如果有人能在这些方面提供帮助,我将不胜感激-

1) 为什么add服务调用不在编译代码时向atom添加一个向量-

  • 添加服务
    定义为
    fn
  • 添加服务
    定义为

2) 如何使其工作:)

这取决于您是否在project.clj中将
:aot
设置为
:all

如果
:aot
:all
,则函数调用将在repl启动后立即执行,否则您将需要加载
ex.second
命名空间(例如:使用
使用
)。加载将导致编译ns,并在jvm中加载相应的类,然后执行函数调用

此外,函数调用不会在编译时发生,而是在jvm加载已编译类(表示名称空间)时发生

更新(基于评论):

如果你把它变成一个宏,那么你也需要考虑AOT的事情。 如果aot被设置为编译名称空间,那么lein将创建一个jvm,在其中加载代码,调用clojure编译器,它将读取代码,执行宏并编译代码,此时这个jvm(用于编译代码)将拥有

服务
atom,因为宏的执行,但这个jvm只是用于编译。然后,lein将为run命令创建另一个jvm,并在该jvm中加载已编译的类,但该jvm不会填充
服务,因为这些类没有任何填充它的代码

如果未设置aot,则宏将起作用,因为读取、宏扩展和编译过程将在lein运行jvm中发生,但仅当您导致加载ns时


就“不加载ns”而言,您可以做的是将
ex.second
放在project.clj的
:aot
中,这取决于您是否已将
:aot
设置为
:all
在project.clj中

如果
:aot
:all
,则函数调用将在repl启动后立即执行,否则您将需要加载
ex.second
命名空间(例如:使用
使用
)。加载将导致编译ns,并在jvm中加载相应的类,然后执行函数调用

此外,函数调用不会在编译时发生,而是在jvm加载已编译类(表示名称空间)时发生

更新(基于评论):

如果你把它变成一个宏,那么你也需要考虑AOT的事情。 如果aot被设置为编译名称空间,那么lein将创建一个jvm,在其中加载代码,调用clojure编译器,它将读取代码,执行宏并编译代码,此时这个jvm(用于编译代码)将拥有

服务
atom,因为宏的执行,但这个jvm只是用于编译。然后,lein将为run命令创建另一个jvm,并在该jvm中加载已编译的类,但该jvm不会填充
服务,因为这些类没有任何填充它的代码

如果未设置aot,则宏将起作用,因为读取、宏扩展和编译过程将在lein运行jvm中发生,但仅当您导致加载ns时


至于“不加载ns”,您可以做的是将
ex.second
放在project.clj的
:aot
中。谢谢@Ankur,这非常有帮助。因此,如果我使用宏或fn,在用法上没有区别。(是的,一个宏将在编译时和JVM中的加载时进行比较)为了两者都能工作,我仍然必须:使用ns。有没有比只需要ns更好的模式?或者:aot是一个更好的选择?核心ns是否默认编译?我已经尽了最大努力。这是一个非常详细的答案,谢谢。那么默认情况下core.clj总是在jvm中编译和加载吗?还有,lein repl做什么,它是否也只是编译并加载jvm中的核心?lein repl将启动jvm(使用java命令),根据project.clj设置类路径(此jvm的类路径中有clojure jar,该类路径在您的project.clj中指定。lein有自己的clojure jar)。如果您在项目中引用的clojure.jar是aot编译的,那么已经编译了core.clj,否则它是在ns负载上编译的。顺便说一下,Clojure.jar是预编译的,因此core.clj已经以编译的形式存在了。我问这个问题的原因是bcoz如果我需要我核心的(例如,第一个),我看到fn呼叫已经发出。那么这是否意味着任何项目的ex.core ns都会自动加载和编译?如果project.clj中的
:main
设置为core ns,则repl将在此ns中启动,因此加载core NStanks@Ankur非常有用。因此,如果我使用宏或fn,在用法上没有区别。(是的,一个宏将在编译时和JVM中的加载时进行比较)为了两者都能工作,我仍然必须:使用ns。有没有比只需要ns更好的模式?或者:aot是一个更好的选择?核心ns是否默认编译?我已经尽了最大努力。这是一个非常详细的answ