我该如何处理Clojurescript宏中所需的Clojurescript代码?

11

假设我有一个X.clojurescript和一个X.clojure名称空间,X.clojurescript中的所有内容都是Clojurescript代码,X.clojure中的所有内容都是Clojure代码。不幸的是,我不能直接在Clojurescript中定义宏,我必须在Clojure中定义它们,然后使用"bring them into a Clojurescript namespace"将它们带入Clojurescript命名空间。

(ns X.clojurescript.abc
  (:require-macros [X.clojure.def :as clj]))

这很好。但是,如果宏(在X.clojure中定义)需要引用Clojurescript命名空间(X.clojurescript)中定义的内容怎么办?问题在于,Clojure编译器在解析其他命名空间时不会查找我的Clojurescript命名空间(一个单独的目录)。

我通过在我的Clojure代码中创建一个与Clojurescript中存在的相同命名空间和所需定义的命名空间来解决了这个问题,但这似乎有点愚蠢。因此,例如,如果我在宏中需要X.clojurescript.abc.y,我将在Clojure端创建另一个命名空间,在其中为X.clojurescript.abc的我的Clojure版本定义一个虚拟的y;有点愚蠢。

如何处理需要引用Clojurescript侧某些东西的宏?


使您的宏接受ClojureScript中所需的所有内容作为参数。如果您能添加一些代码,那么回答您的具体问题将更加容易。 - Ankur
2
我不认为我理解你的问题。您的宏必须生成代码,然后在clojurescript中进行评估。因此,如果您必须引用任何clojurescript def,那么在宏的扩展中生成符号是否足够? - KIMA
你是在宏展开时需要引用Clojurescript端的某些内容,还是这将成为输出代码中的一部分? - Ankur
1个回答

6

仅当宏在定义时使用特定命名空间的代码来生成其返回的符号列表时,宏才需要特定命名空间。

您可以在repl中使用这些示例进行跟随:

(defmacro foo
  [a]
  `(bar/bar ~a))

即使bar不是一个已定义的命名空间,foo的定义也将被编译。

(foo :a)

现在调用foo会失败,因为您尚未定义bar名称空间或函数。

(ns bar)
(defn bar
  [x]
  [x x])

在 bar 命名空间中定义了 bar

(ns user)
(foo :a)

=> [:a :a]

注意,bar在foo定义时不需要存在。实际上,在foo定义时命名空间甚至不需要存在。


编译只是一方面,但在ClojureScript端需要一个库怎么办?在上面的例子中,似乎需要在调用foo宏的ClojureScript模块中要求bar命名空间,这意味着调用模块必须知道有关宏的实现细节。 - Kevin Albrecht
我提到的问题的一个例子是Hiccups库遇到的。你可以在这里看到他们的解决方案,有点hacky:https://github.com/teropa/hiccups#usage - Kevin Albrecht
1
我认为这是clojurescript实现中存在的一个根本性问题。我建议采用我认为最好的方法来处理它,但我也理解这并不理想。但从根本上讲,这与在纯clojure代码中使用宏的方式没有什么区别——宏在调用时查找其生成符号的函数。 - noisesmith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接