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 返回一个新变量,而不是原始变量。这会丢弃用户提供的元数据。
    • 因此,宏作者无法观察用户提供的元数据以执行宏展开时的自定义逻辑

请求

使 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 更受欢迎。

...