gpt4 book ai didi

clojure - 在 Clojure 中的嵌套宏之间传递编译时状态

转载 作者:行者123 更新时间:2023-12-04 18:03:02 24 4
gpt4 key购买 nike

我正在尝试编写一个可以以全局和嵌套方式使用的宏,如下所示:

;;; global:
(do-stuff 1)

;;; nested, within a "with-context" block:
(with-context {:foo :bar}
(do-stuff 2)
(do-stuff 3))

嵌套使用时, do-stuff应该可以访问 {:foo :bar}with-context 设置.

我已经能够像这样实现它:
(def ^:dynamic *ctx* nil)

(defmacro with-context [ctx & body]
`(binding [*ctx* ~ctx]
(do ~@body)))

(defmacro do-stuff [v]
`(if *ctx*
(println "within context" *ctx* ":" ~v)
(println "no context:" ~v)))

但是,我一直在尝试转移 ifdo-stuff 内从运行时到编译时,因为是否 do-stuff正在从 with-context 的正文中调用或 global 是在编译时已经可用的信息。

不幸的是,我一直没能找到解决方案,因为嵌套宏似乎在多个“宏扩展运行”中得到扩展,所以 *ctx* 的动态绑定(bind)(在 with-context 中设置)在 do-stuff 时不再可用得到扩展。所以这不起作用:
(def ^:dynamic *ctx* nil)

(defmacro with-context [ctx & body]
(binding [*ctx* ctx]
`(do ~@body)))

(defmacro do-stuff [v]
(if *ctx*
`(println "within context" ~*ctx* ":" ~v)
`(println "no context:" ~v)))

任何想法如何做到这一点?

还是我的方法完全疯狂,并且有一种模式可以将状态以这种方式从一个宏传递到嵌套宏?

编辑 :
with-context的正文应该能够处理任意表达式,而不仅仅是 do-stuff (或其他上下文感知功能/宏)。所以这样的事情也应该是可能的:
(with-context {:foo :bar}
(do-stuff 2)
(some-arbitrary-function)
(do-stuff 3))

(我知道 some-arbitrary-function 是关于副作用的,例如它可能会向数据库写入一些内容。)

最佳答案

当代码被宏扩展时,Clojure computes一个 fixpoint :

(defn macroexpand
"Repeatedly calls macroexpand-1 on form until it no longer
represents a macro form, then returns it. Note neither
macroexpand-1 nor macroexpand expand macros in subforms."
{:added "1.0"
:static true}
[form]
(let [ex (macroexpand-1 form)]
(if (identical? ex form)
form
(macroexpand ex))))

当您退出宏时,您在执行宏期间建立的任何绑定(bind)都不再存在(这发生在 macroexpand-1 内)。当内部宏被扩展时,上下文早已不复存在。

但是,您可以调用 macroexpand直接,在这种情况下绑定(bind)仍然有效。但是请注意,在您的情况下,您可能需要调用 macroexpand-all .
This answer解释 macroexpand 之间的区别和 clojure.walk/macroexpand-all :基本上,您需要确保所有内部形式都是宏扩展的。 macroexpand-all 的源代码显示 how it is implemented .

因此,您可以按如下方式实现宏:
(defmacro with-context [ctx form]
(binding [*ctx* ctx]
(clojure.walk/macroexpand-all form)))

在这种情况下,动态绑定(bind)应该从内部宏内部可见。

关于clojure - 在 Clojure 中的嵌套宏之间传递编译时状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39943529/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com