Clojure 2024调查中分享您的想法!

欢迎!有关此操作的更多信息,请参阅关于页面。

+1 投票
ClojureScript

问题陈述

编写 clojurescript 宏的作者没有将符号解析为 var 的设施。也就是说,在宏展开时将符号展开为其完全限定形式。

+     ;; -> cljs.core/+
s/def ;; -> cljs.spec.alpha/def

在 JVM 中,这当然是一个可能性。

但在 cljs 中没有这样的可能性,至少不是干净的方法。

  • 存在一个名为 cljs.core/resolve 的宏,但我认为它旨在在 cljs 代码中使用,而不是针对 cljs 的宏。
    • 特别是,cljs.core/resolve 预期一个 quoted 符号,这对宏作者来说是一个不必要的限制。
  • cljs.core/resolve 返回一个新的 var,而不是原始的 var。这导致丢失用户提供的元数据。
    • 因此,宏作者无法观察用户提供的元数据以进行宏展开时的自定义逻辑

请求

使 cljs.core/resolve 更灵活,或者创建一个专门针对宏作者的独立解析函数

用例

我有一些现有的 JVM 宏,使用了在宏展开时使用 resolve,需要将其迁移到 cljs。即,此请求来自实际需求。

解决方案

以下函数可以顺利工作,满足描述的需求。

然而,它可以被认为是玩 cljs 内部,因此可能会在新 cljs 版本中出现问题。

(defn cljs-resolve
  [env sym]
  (let [[var meta] (try
                     (let [var (cljs.analyzer/resolve-var env sym (cljs.analyzer/confirm-var-exists-throw))]
                       [var (cljs.analyzer/var-meta var)])
                     (catch Throwable t
                       [(cljs.analyzer/resolve-var env sym) nil]))]
    (some-> var
            :name
            (vary-meta assoc :cljs.analyzer/no-resolve true)
            (vary-meta merge meta))))

2 个答案

+1 投票

您的用例是什么,为什么 cljs.anaylzer/resolve-var 不可行?

cljs.analyzer/resolve-var 应该能够提供你需要的一切。它返回一个包含分析器中所有可用信息的映射。它确实有一个 :meta 键。不清楚为什么你在实现中要进行所有这些操作。

cljs.core/resolve 实际上只是一个用于代码拆分的辅助函数,甚至其在那里的使用也是值得怀疑的,请不要使用它。在宏中使用 cljs.analyzer/resolve-var 是可以接受的。

by
感谢 Thomas,我会确保检查 `resolve-var` 的。我不知道它,并且出于某种原因,我以为 `cljs.core/resolve` 是唯一提供的功能。
by
我认为你知道因为它有一个“修正”示例使用它。可以调用 cljs.analyzer/resolve-var,并带有宏的 &env 和一个符号。
by
抱歉,是的,我确实使用了 (并且因此知道了) `resolve-var`。  我有一种印象,以为这是一个实现细节;我想这并非如此?

我记得是通过查看源代码找到 `resolve-var` 的,而不是通过在文档中找到它。
0
by

你看过 cljs.analyzer.api/resolve 吗?它比调用 cljs.analyzer/resole-ar 更受欢迎。

...