Clojure宏在运行罐子时很奇怪

sip*_*uel 4 macros clojure uberjar leiningen

下面是一个简单的Clojure应用程序示例lein new mw:

(ns mw.core
  (:gen-class))

(def fs (atom {}))

(defmacro op []
  (swap! fs assoc :macro-f "somevalue"))

(op)

(defn -main [& args]
  (println @fs))
Run Code Online (Sandbox Code Playgroud)

project.clj我有

:profiles {:uberjar {:aot [mw.core]}}
:main mw.core
Run Code Online (Sandbox Code Playgroud)

在REPL中运行时,评估@fs返回值{:macro-f somevalue}.但是,运行一个uberjar收益率{}.如果我改为op定义defn而不是defmacro,那么fs当从uberjar运行时再次有适当的内容.这是为什么?

我隐约意识到这与AOT编译有关,并且宏编译在编译阶段之前发生,但显然我对这些事情的理解是缺乏的.

我在尝试部署使用非常好的mixfix库的应用程序时遇到了这个问题,其中mixfix运算符是使用全局原子定义的.我花了很长时间才将问题与上面提到的例子隔离开来.

任何帮助将不胜感激.

谢谢!

Leo*_*tny 6

这里真正的问题是你的宏不正确.你忘了添加反引号字符:

(defmacro op []
  `(swap! fs assoc :macro-f "somevalue"))
; ^ syntax-quote ("backquote")
Run Code Online (Sandbox Code Playgroud)

这个操作叫做syntax-quote,这里非常重要,因为clojure中的宏在编译时会修改你的代码.

因此,结果你得到了一个不纯的宏,fs只要编译代码就修改原子.

由于您的宏不生成任何代码,因此(op)在您的示例中调用什么都不做(只有它的编译才能执行).它似乎在REPL中工作,因为编译和执行由同一个clojure实例处理(详见Timur的答案).