请在 2024 年 Clojure 状态调查! 中分享您的想法。

欢迎!请参阅关于页面,了解有关此内容的更多信息。

+1
ClojureScript

问题陈述

为 ClojureScript 编写宏的作者没有将符号解析为变量的功能。也就是说:在宏展开时将符号展开为其完全限定形式

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

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

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

  • 存在一个 cljs.core/resolve 宏,但我可以说,它是用于 cljs 代码的,而不是针对 cljs 的宏。
    • 特别是,cljs.core/resolve 期望一个引号化的符号,这对宏作者来说是一个不必要的限制。
  • 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
我以为你了解它,因为 "Workaround" 示例使用了它。可以使用宏 &env 和一个符号调用 cljs.analyzer/resolve-var。
by
抱歉,是的,我确实使用了(并且因此了解)`resolve-var`。我认为这只是一个实现细节;我想不是这种情况吧?

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

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

...