You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Clojure宏展开阶段获取另一宏的元数据?

宏展开阶段读取Clojure宏的元数据

在个人项目中定义了多个Clojure宏,希望在宏展开阶段读取其他宏定义的元数据,以此让当前宏根据输入形式做不同展开。虽然展开后读取元数据的方案更简单,但想探索宏展开阶段实现的可能性。

示例宏定义

(defmacro stackoverflow 
  {:example 23} 
  [& args] 
  (comment "This is just an example"))

非宏展开阶段的可行读取方式

普通函数读取宏元数据

(defn- -example?
  [form-var]
  (-> form-var
      meta
      :example
      some?))

;; 调用结果
=> (-example? #'stackoverflow)
true

普通宏读取元数据

(defmacro example?-macro[form] 
  `(-example? (var ~form)))

;; 调用结果
=> (example?-macro stackoverflow)
true

宏展开阶段读取的问题

尝试直接在宏展开阶段判断时出现错误:

(defmacro test-example? [form]
  (if (example?-macro form)
    (println "It is indeed an example")
    (println "It is not an example!")))

;; 错误信息
> Unable to resolve var: form in this context

核心需求:在宏内不展开输入宏的情况下,在宏展开阶段获取其var的元数据,期望的理想实现类似:

;; 期望的行为
(defmacro imagining-solution
  [form]
  (if (:example `(meta (var ~form)))
    (println "It is indeed an example")
    (println "It is not an example!")))

宏展开阶段读取元数据的实现方法

要在宏展开阶段获取目标宏的元数据,关键是在宏的展开代码中,通过resolve函数在编译期找到目标var,再读取其元数据。resolve需要传入符号,因此要确保输入的form是一个符号:

(defmacro test-example? [form]
  (let [target-var (resolve form)]
    (if (-> target-var meta :example some?)
      (println "It is indeed an example")
      (println "It is not an example!"))))

;; 调用测试
(test-example? stackoverflow)
;; 输出:It is indeed an example

补充说明

  • resolve在宏展开阶段(编译期)执行,直接查找当前环境中名为form的var,无需等到运行时
  • 需确保form是一个符号(如stackoverflow),若输入是复杂形式,需先做符号提取处理
  • 该方式不会展开目标宏,仅读取其var的元数据,完全符合宏展开阶段处理的需求

内容的提问来源于stack exchange,提问作者Roman Makhlin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 13:12:15