【问题标题】:How to expand macros in ClojureScript's cljs.core namespace如何在 ClojureScript 的 cljs.core 命名空间中展开宏
【发布时间】:2013-07-05 14:43:46
【问题描述】:

我很好奇某些宏在做什么,并尝试致电(macroexpand-1) 获取更多信息。但是,我对如何扩展 ClojureScript 中的内置宏感到有些困惑,尤其是 cljs.core 命名空间中的宏。根据文档,ClojureScript 宏是用 Clojure 编写的,因此必须在 Clojure REPL(而不是 ClojureScript REPL)中进行测试,这是我一直在尝试的地方。

在我的 ClojureScript 项目目录中运行 lein repl,我已经尝试过:

=> (require 'cljs.compiler)
=> (require 'cljs.core)
=> (macroexpand-1 '(cljs.core/int 99.9))
(macroexpand-1 '(cljs.core/int 99.9))
(cljs.core/int 99.9)

为什么返回(cljs.core/int 99.9)?基于ClojureScript source,该宏不应该扩展为(bit-or ~x 0) 之类的东西吗?

当我扩展非 ClojureScript 宏时,例如 (macroexpand-1 '(when (even? 2) (println "2 is even"))),扩展似乎工作正常。

似乎我在概念上遗漏了一些东西......

【问题讨论】:

    标签: clojure clojurescript


    【解决方案1】:

    您很可能正在使用早于this commit 的ClojureScript 版本,它引入了int 宏。尝试将[org.clojure/clojurescript "0.0-1835"] 添加到您的:dependencies

    此外,虽然这与此处无关,但一般来说,您应该使用 ClojureScript 的 macroexpand-1 而不是 Clojure 的用于这样的测试:

    (require '[cljs.compiler :as comp]) ; must be required before cljs.core
    (require '[cljs.core :as core])     ; the macros live here
    (require '[cljs.analyzer :as ana])  ; macroexpand-1 lives here
    
    ;; ClojureScript's macroexpand-1 takes an environment as its first
    ;; argument; here's a useful initial environment:
    (ana/macroexpand-1 {:locals {} :context :expr :ns 'cljs.user} '(int 5))
    ;= (cljs.core/bit-or 5 0)
    

    【讨论】:

    • 啊,现在有道理了!谢谢!
    • 有趣的是,我没想到 ClojureScript 有自己的macroexpand-1,因为它没有自己的defmacro
    • 刚刚意识到 Clojure 的 macroexpand-1 实际上应该在这里为您工作,请参阅我对 dnolen 答案的评论。由于the commit introducing the int macro 的发布日期为 2013 年 2 月 22 日,您可能只是在使用旧版本;使用0.0-1835(截至目前最新),您应该会看到您期望的结果。 ClojureScript 的macroexpand-1 通常仍然需要,因为 ClojureScript 环境可能与更复杂的情况相关。
    • 编辑了答案以包含上述评论。至于拥有自己的 macroexpand-1 的 ClojureScript:它是必需的,因为 ClojureScript 需要自己的逻辑来进行扩展器查找(请参阅 cljs.analyzer/get-expander)。它还让扩展器相信,无论当前的 ClojureScript 命名空间被调用什么,当前命名空间实际上都是被调用的,以使其在一定程度上了解将代码输出到的实际 ClojureScript 环境。
    • 明白了。现在这一切都变得更有意义了。在试图弄清楚为什么我看不到 int 宏时,我在您发布原始答案之前更新了我的 ClojureScript 依赖项。巧合让我看起来不得不使用 ClojureScript 的 macroexpand-1,但你是对的:至少对于 int,这只是一个没有足够新的 jar 的情况。
    【解决方案2】:

    int 没有编译器宏。

    【讨论】:

    • 其实有,只是一定要使用正确的macroexpand-1
    • 嗯,实际上常规的macroexpand-1 在这种情况下也应该可以工作(ClojureScript 环境在这里是无关紧要的,除了bit-or 宏的存在,但这是在cljs/core.clj 前面定义的)。如果 OP 没有看到这一点,他可能使用的版本早于引入 int 宏(在 this commit 中)。所以这个答案对于旧版本是非常正确的。很抱歉造成混乱。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-17
    • 1970-01-01
    • 1970-01-01
    • 2016-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多