【发布时间】:2017-05-15 17:56:18
【问题描述】:
我有一个 CLJC 文件,它在 Clojure 中产生以下所需的输出:
(ns myproj.macros-ns)
(defmacro inner-macro [s]
`['(my-ns/my-fn) :from ['~s :all]])
(defmacro outer-macro [y xs]
`(into ['~y '~'<-] (eval '~xs)))
(defmacro macro-context [other-macros]
(let [symbols (eval other-macros)
_ (println "Expanded in macro context" symbols)]
{:result `(list '~symbols '~'+ '~'further-rearrangement)}))
(macro-context (outer-macro ?sym-a (inner-macro ?sym-b)))
Expanded in macro context [?sym-a <- (my-ns/my-fn) :from [?sym-b :all]]
=> {:result ([?sym-a <- (my-ns/my-fn) :from [?sym-b :all]] + further-rearrangement)}
我的问题是:如何在 Clojurescript 中获得相同的结果?
我的 CLJS 文件如下所示:
(ns myproj.app-ns
(:require-macros [myproj.macros-ns :refer [outer-macro
inner-macro
macro-context]]))
(enable-console-print!)
(macro-context (outer-macro ?sym-a (inner-macro ?sym-b)))
我得到的错误是:
clojure.lang.ExceptionInfo: java.lang.RuntimeException: Unable to
resolve symbol: outer-macro in this context, compiling:
(/private/var/folders/2g/sfp74ftj6_q1vw51ytjbgvph0000gn/T/form-
init4244939051951953637.clj:13:3) at line 12
test/macros/cljs/myproj/app_ns.cljs
我最终想要做什么以及为什么?
我正在编写一个包装https://github.com/cerner/clara-rules 的框架。 Clara 有自己的宏 defrule,它使用以下 DSL 语法
(defrule my-rule
[?fact <- (my-ns/my-fn) :from [:all (= ?e (:e this))]
...
我有一个将以下内容扩展为上一个的宏:
(macro-context my-rule
[?fact <- (my-ns/my-fn) :from [?e :all]]
...
执行此操作的宏基本上是上面更一般示例中的macro-context。当我只解析这样的语法时,我不会调用eval 或macroexpand。我可以将所有内容都视为一个符号,将其重写为 Clara 的 DSL,然后将其传递给 defrule。
这就是我认为失败的地方:
(macro-context
[(outer-macro ?fact (inner-macro ?e))]
...
在 macro-context 宏内部,outer-macro 和 inner-macro 未被评估,此时我需要它们的扩展。通过调用 eval,我可以在 Clojure 中得到它,但由于某种原因,在编译 Clojurescript 时,我收到“在这种情况下无法解析符号 outer-macro。
【问题讨论】:
-
这是一种非常奇怪的解决问题的方法,并且有点不清楚是什么实际问题推动了这个解决方案。您提供了“这是我试图做的一件事,但没有成功”,这让我想“是的,那肯定行不通,但我不知道还有什么建议,因为我没有”不知道你为什么要这样做”。您的解决方案对于 clj-jvm 来说也是错误的,而您只是巧合地侥幸逃脱。但同样,如果不知道在宏观时间生成这些奇怪形式的意义何在,我什至不能肯定地说。
-
感谢您的回复!我将提供有关我要解决的问题的更多背景信息和一般信息。
-
您应该使用
macroexpand而不是eval。 -
@ClojureMostly 不,这不是一个正确的解决方案。如果
f和g都是宏,那么(macroexpand '(f (g x)))与(eval '(f (g x)))不同(或者通常写(f (g x))):第一个不扩展g,而最后两个做。
标签: clojure macros clojurescript