我可以从Clojure中的宏中引用宏吗?
克罗朱尔。草书的答复。视窗10。所有都是最新的。我可以从Clojure中的宏中引用宏吗?,clojure,macros,Clojure,Macros,克罗朱尔。草书的答复。视窗10。所有都是最新的。 这是我的“基本”宏: (defmacro PutProp! [Sym Val PName] `(reset-meta! (var ~Sym) (assoc (meta (var ~Sym)) ~PName ~Val))) 我不知道这样做是否正确,我想做的就是用新的Val值修改Sym的元数据键名PName。我在这方面是新手,我肯定我已经跳进了游泳池的最深处。我之所以使用宏,是因为我认为它可以避免复杂的变量绑定问题,而我在Clojure中不了解
这是我的“基本”宏:
(defmacro PutProp! [Sym Val PName]
`(reset-meta! (var ~Sym) (assoc (meta (var ~Sym)) ~PName ~Val)))
我不知道这样做是否正确,我想做的就是用新的Val值修改Sym的元数据键名PName。我在这方面是新手,我肯定我已经跳进了游泳池的最深处。我之所以使用宏,是因为我认为它可以避免复杂的变量绑定问题,而我在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进行宏扩展-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核心函数。请给我少一点。求你了 这不会宏扩展PutProp!宏 是,
macroexpand-1
只执行一次宏扩展。宏扩展的整个过程是一个不动点计算,其中每棵树都被扩展,直到它达到一个无法再扩展的形式
您可能想使用
此外,宏中的输入列表是表达式列表,您希望在宏扩展时获取该列表的第一个和下一个
(first ~@L)
上述内容扩展为:
(clojure.core/first Sym :VName :VValue)
实际上,您只需要Sym
,即:
~(first L)
使用另一个宏定义宏是完全合法的(常见的)
您可以看到IMHO逐步建立宏的最佳方法的示例
我不喜欢使用
macroexpand-*
函数。上面链接中的答案使用带有println
和friends的简单帮助函数,这样您就可以在宏写入过程中一步一步地看到发生了什么。享受吧 您是否可以添加所需用例和结果的示例?除非我遗漏了什么,PutProp
不需要是宏,可以作为一个简单的函数编写(更可取)。此外,还可以是一个小的样式点。Clojure通常使用“kabob case”,比如def meta代码>用于名称。CamelCase名称,如DefMeta
通常保留用于与Java类或它们的Clojure表兄弟、记录交互。如果您只想再进行一次扩展,为什么不调用第一次的结果macroexpand-1
?谢谢!宏扩展的想法宏扩展非常有用。谢谢。我想我已经让它做了我想做的。“是的,它是合法的。”这是最有用的信息。我将在稍后跟进该链接。