Clojure。草书。复制。 Windows 10。全部是最新的。
这是我的“基本”宏:
(defmacro PutProp! [Sym Val PName]
`(reset-meta! (var ~Sym) (assoc (meta (var ~Sym)) ~PName ~Val)))
我不知道这在做我想做的事情时是否正确,即使用新的 修改 Sym 的元数据键名 PName Val 值。我是新来的,我确信我已经跳进了游泳池的深处。我正在使用宏,因为我认为它可以避免我在 Clojure 中不理解的混乱的变量绑定问题。
然后我写了另一个宏来在一次调用中定义很多元数据:
(defmacro DefMeta! [L] ;; Given a symbol (first L), define metadata for it given in (next L).
`(let [S (first ~@L)] ;; The symbol we're modifying is the first element in list L.
(map (fn [[K V]] (PutProp! S V K)) (next ~@L)))) ;; (next L) is the list of key/value pairs.
我也不确定这是我想写的。 在 REPL 工作,我定义了一个符号:
(def Sym 0)
然后我做一个 DefMeta 的 macroexpand-1!:
(macroexpand-1 '(DefMeta! [Sym :VName :VValue]))
我得到以下信息:
(clojure.core/let
[thic.core/S (clojure.core/first Sym :VName :VValue)]
(clojure.core/map
(clojure.core/fn [[thic.core/K thic.core/V]] (thic.core/PutProp! thic.core/S thic.core/V thic.core/K))
(clojure.core/next Sym :VName :VValue)))
它不会宏扩展 PutProp!宏。
我难住了。我有四本关于 Clojure 编程的书,没有 提到宏调用中的宏调用。它甚至合法吗?如果是这样,我如何完全扩展内部宏,以便我可以查看我写的内容是否是我想要的? [...程序员长期存在的问题...]
PS 我尝试了 macroexpand-all
并且我对一切的宏扩展感到不知所措,甚至是 Clojure 核心功能。
请少一点。请?
答案 0 :(得分:3)
它不会宏扩展 PutProp!宏。
是的,macroexpand-1
只执行一次宏展开。宏展开的整个过程是一个定点计算,每棵树都被展开,直到达到无法展开的形式。
您可能想要使用 macroexpand-all
另外,你的宏中的输入列表是一个表达式列表,你想在宏展开时取这个列表的第一个和下一个。
(first ~@L)
以上扩展为:
(clojure.core/first Sym :VName :VValue)
您实际上只想要Sym
,即:
~(first L)
答案 1 :(得分:2)
宏的定义使用另一个宏是完全合法的(并且很常见)。
您可以看到一个示例,说明逐步构建宏的最佳方式(恕我直言)in this question。
我不喜欢使用 macroexpand-*
函数。上面链接中的答案使用带有 println
和朋友的简单辅助函数,因此您可以在宏编写过程中一步一步地看到发生了什么。享受!