我有一个项目,通过CLJX同时针对Clojure(JVM)和ClojureScript。
我有一个带有thunk的宏并创建一个IDeref
实例,以便在每次取消引用时使用deref
或@
来执行该thunk。
由于它是一个宏,它必须进入 .clj 文件。问题是Clojure和ClojureScript的IDeref
接口不同。在Clojure中我需要生成这个:
(reify clojure.lang.IDeref
(deref [_] thunk))
在ClojureScript中我需要生成这个:
(reify IDeref
(-deref [_] thunk))
由于这是一个宏,我不能使用cljx中的类似featuer-expression的语法(例如#+cljs -deref
)来协调我的两个目标平台的代码。这就是我最终做的事情:
(defmacro make-thunk [exp]
`(reify ~params/IDeref-interface
(~params/IDeref-method [_#] ~exp)))
然后我在clj和cljs源树中都有一个单独的 params.clj ,每个源树都有一个def
用于每个需要的符号。
这很有效,但它真的很难看,感觉就像是一个肮脏的黑客。
我真的想将所有宏保存在同一名称空间中。我宁愿不必在单独的文件中为我的宏定义每个与平台相关的符号。我已经在两个源树中有与平台相关的 compat.clj 和 compat.cljs 文件。必须添加更多文件以支持依赖于平台的宏才开始让事情变得混乱。
这个问题是否有更清洁的解决方案?
答案 0 :(得分:2)
这应该可以解决问题:
(defn compiling-cljs?
"Returns true if we seem to be compiling ClojureScript, false otherwise.
This is a Clojure function, meant to be called by macros targeting both
Clojure and ClojureScript."
[]
(if-let [cljs-ns-var (resolve 'cljs.analyzer/*cljs-ns*)]
(some? @cljs-ns-var)
false))
像这样使用:
(defmacro foo []
(if (compiling-cljs?)
1
2))
(我觉得这个问题以前已经解决了,但似乎无法找到参考。)
答案 1 :(得分:2)
在宏的主体内部,{C <1}}在ClojureScript中展开时会很简洁,但在Clojure中则不行。
这是目前最好的做法&#34;用于编写特定于平台的宏:
(:ns &env)