请在2024 Clojure 实态调查中分享您的想法!

欢迎!请访问关于页面以获取更多关于如何使用本站的信息。

0
ClojureScript

我在 clojurescript 中工作,其中 ns-interns 是一个宏。

我试图编写一个宏,以获取命名空间内部的绑定信息,但我在编译时无法操纵这些绑定。

(defmacro my-macro [namespace]
   (let [mappings (ns-interns namespace)]
           ; do stuff
       ))

(my-macro 'mylib.hi)

问题在于,上面的代码失败,因为 ns-interns 宏认为它正在处理符号 namespace,而不是传递给 my-macro 的命名空间。

我可以尝试

[mappings `(ns-interns ~namespace)]

,但是然后我无法在编译时展开宏到一个可以用来生成代码的映射——我只能在生成的代码中“打印”它。我尝试使用 macroexpandmacroexpand-all,但这对我不起作用——我无法使用它们来获取 ns-interns 的结果以用于我的宏。

然而,宏可以展开,因为我下面的代码将生效,如果我使用硬编码的命名空间符号。问题在于,因为我想将外部宏的参数传递到内部宏中。正确的方法是什么,在 Clojurescript 中,我想要在编译时获取并操作命名空间的变量?

(defmacro my-macro [namespace]
   (let [mappings (ns-interns 'mylib.hi)]
     ; do stuff
   )
)

2 答案

0

编辑了

我认为这是不可能的。我所能做到的最接近的是

(defmacro example-macro [ns]
  (let [x (list 'cljs.core/ns-interns ns)
        ]
    `(defmacro ~(symbol "example") []
       (let [y# ~x]
         5
         )
       )))

然后从另一个命名空间调用(example-macro 'my.ns)来生成内部宏。但是Clojure会报告一个错误,说它无法解析传递给它的命名空间的variable。我猜这意味着在内部宏中,它成功地将ns-interns展开为符号-变量映射,但在编译的后续步骤中被销毁了。

因此,我现在相信,在ClojureScript中,即使在编译时,也不能获取任何有关命名空间的数据并用来生成代码。

0

在CLJS中,vars不是直接在运行时实体化的。在宏中,你可以从分析器数据中获取它们。

你可以在ns-interns宏本身中找到如何实现的例子。你在你的宏中想要的关键行是(get-in @env/*compiler* [:cljs.analyzer/namespaces ns :defs])

:defs是符号到它们的def数据的映射(例如,名称,元数据等)。

基于ns-interns本身构建将不会工作,但使用其内部实现将允许你访问数据并生成你想要的内容。

谢谢。

你能否快速访问一个像这样外部 cushion 项目的家伙的运行示例?当我尝试在macron中测试`env/*compiler*`(使用shadow-cljs)时,无论是.clj还是.cljc文件,我遇到了“无法将clojure.lang.Atom编译为ClojureScript常量”的错误,或者它会评估为`nil`。当我尝试测试`@env/*compiler*`时,编译器会报告Null Pointer错误。

由于[env.cljc](https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/env.cljc)指出`env/*compiler*`在编译器中是功能上私有的,我以为我在走歪路--就像当我的宏尝试评估它时,变量没有被绑定。

如果没有链接,我会很感激任何关于编译错误对宏中“有效代码”含义的思考。

----------------------------

例如,即使在 .cljc 文件中引入`cljs.env`和`cljs.compiler`,展开此代码会使`x`评估为nil

(core/defmacro get-ns-interns [namespace]
  (core/let [x env/*compiler* ]
    `(let []
       ~x
      )
    )
  )
by
你需要从原子中获取数据,并使用这些数据生成你需要的任何代码。实际上与`ns-interns`宏是一样的,你在编译器项目内部或外部操作的方式没有区别。如果你想保证“安全”,请使用`cljs.analyzer.api`命名空间中的内容,而不是直接挖掘原子,但据我所知,这样做是可以的。
...