【发布时间】:2026-01-07 10:05:01
【问题描述】:
我正在尝试定义这样的宏:
(defmacro foo-macro
"[name] is the name of the function to define
[meta-data] is the map that defines the meta-data of the function"
[name meta-data]
(let [vals (gensym "label-")]
`(def ~name
^@~meta-data
(fn [~vals] (eval nil)))))
但是,我收到此编译错误:
未处理的 java.lang.IllegalArgumentException 元数据必须是 符号、关键字、字符串或映射
我认为这很正常。但是,我不确定如何使这样的宏工作,或者是否可能。
注意:我不想使用with-meta。阅读此其他问题的解决方案的修订以了解原因:Clojure: issues getting the symbol of a function in a looping context。
我使用 with-meta 的唯一原因是,如果你有办法让它返回一个非 AFunc 标识符。
【问题讨论】:
-
宏是干什么用的?也许还有另一种方法可以完成您的需求,您能否更具体地了解用例?
-
@DiegoBasch 我需要的是一个创建函数的宏。然后我想将元数据附加到该函数对象(而不是它的 Var)。但是,如果我使用
with-meta而不是^{},那么我会得到#< clojure.lang.AFunction$1@15ab1764>作为该对象的引用,而不是像#<core$foo user.core$foo@66e37466>这样更易于阅读的东西。即使文档说这两种方法没有区别,区别似乎是with-meta返回的内容与^{}宏不一样(不是同一个对象引用) -
@DiegoBasch 告诉我是否清楚,否则我将通过更新问题本身再次尝试。
-
您必须在 ^ 之后包含错误中的一项,因为 ^ 是阅读器宏。您可以执行 ^{~meta-key ~meta-val} 之类的操作,或者使用字符串获取 {:tag "something"}。我的问题更多是关于为什么需要使用宏生成函数,因为在该特定函数中没有任何内容需要宏。
-
我不确定
^{~meta-key ~meta-val}会起作用,因为meta-data参数本身就是一个映射(用于向函数提供元数据。我需要做的是让人们创建一系列函数,但具有特定模式。所以我使用宏来强制遵循该特定模式。我的问题是我让他们使用地图定义所有必要的元数据。但是,我认为我可以将关键字参数用于常见和更静态的元数据值,然后使用可选的元数据参数,如果需要,他们可以添加更多。