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

感谢 Thomas,我会确保查看 `resolve-var`。我没有意识到它的存在,本来以为 `cljs.core/resolve` 是唯一可用的功能。
你认为你已经知道这一点,因为“解决方案”示例使用了它。可以调用 cljs.analyzer/resolve-var,传入宏 &env 和一个符号。
抱歉,确实我使用了 `resolve-var`。我记得我是通过查看源代码而不是通过文档发现它的;我想这可能不是实现细节?

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

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

...