使用 cljx 的目标相关宏
Target-dependent macros with cljx
问题描述
我有一个通过 CLJX.
同时针对 Clojure (JVM) 和 ClojureScript 的项目
我有一个宏,它接受一个 thunk 并创建一个 IDeref
实例来在每次取消引用时执行该 thunk(使用 deref
或 @
)。
因为它是一个宏,所以它必须放在 .clj 文件中。问题是 IDeref
接口对于 Clojure 和 ClojureScript 是不同的。在 Clojure 中我需要生成这个:
(reify clojure.lang.IDeref
(deref [_] thunk))
在 ClojureScript 中我需要生成这个:
(reify IDeref
(-deref [_] thunk))
由于这是一个宏,我无法使用 cljx 中的类似特征表达式的语法(例如 #+cljs -deref
)来协调我的两个目标平台的代码。这是我最后做的:
(defmacro make-thunk [exp]
`(reify ~params/IDeref-interface
(~params/IDeref-method [_#] ~exp)))
然后我在 clj 和 cljs 源代码树中都有一个单独的 params.clj,每个源代码树都有一个 def
用于每个需要的符号。
这行得通,但它真的很丑,感觉像是一个肮脏的 hack。
我的问题
我真的很想将我所有的宏都保存在同一个命名空间中。我宁愿不必在单独的文件中为我的宏定义每个平台相关的符号。我在两个源代码树中已经有依赖于平台的 compat.clj 和 compat.cljs 文件。必须添加更多文件来支持依赖于平台的宏开始让事情变得混乱。
这个问题有更简洁的解决方案吗?
这应该可以解决问题:
(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))
(我感觉这个问题之前已经解决了,但是好像找不到参考。)
在宏的主体内,(:ns &env)
在 ClojureScript 中扩展时为真,但在 Clojure 中不为真。
这是目前用于编写平台特定宏的 "best practice":
(defmacro platform []
(if (:ns &env)
:CLJS
:CLJ))
问题描述
我有一个通过 CLJX.
同时针对 Clojure (JVM) 和 ClojureScript 的项目我有一个宏,它接受一个 thunk 并创建一个 IDeref
实例来在每次取消引用时执行该 thunk(使用 deref
或 @
)。
因为它是一个宏,所以它必须放在 .clj 文件中。问题是 IDeref
接口对于 Clojure 和 ClojureScript 是不同的。在 Clojure 中我需要生成这个:
(reify clojure.lang.IDeref
(deref [_] thunk))
在 ClojureScript 中我需要生成这个:
(reify IDeref
(-deref [_] thunk))
由于这是一个宏,我无法使用 cljx 中的类似特征表达式的语法(例如 #+cljs -deref
)来协调我的两个目标平台的代码。这是我最后做的:
(defmacro make-thunk [exp]
`(reify ~params/IDeref-interface
(~params/IDeref-method [_#] ~exp)))
然后我在 clj 和 cljs 源代码树中都有一个单独的 params.clj,每个源代码树都有一个 def
用于每个需要的符号。
这行得通,但它真的很丑,感觉像是一个肮脏的 hack。
我的问题
我真的很想将我所有的宏都保存在同一个命名空间中。我宁愿不必在单独的文件中为我的宏定义每个平台相关的符号。我在两个源代码树中已经有依赖于平台的 compat.clj 和 compat.cljs 文件。必须添加更多文件来支持依赖于平台的宏开始让事情变得混乱。
这个问题有更简洁的解决方案吗?
这应该可以解决问题:
(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))
(我感觉这个问题之前已经解决了,但是好像找不到参考。)
在宏的主体内,(:ns &env)
在 ClojureScript 中扩展时为真,但在 Clojure 中不为真。
这是目前用于编写平台特定宏的 "best practice":
(defmacro platform []
(if (:ns &env)
:CLJS
:CLJ))