我有一个小宏,它将一系列cmds作为clojure的表达式并返回它们的字符串表示。我无法将参数传递给宏 -
(defmacro cmd [& cmds]
(->> (for [v cmds]
(join " " v))
(join "; ")))
(defn install-jive [version]
(cmd
(yum remove jive-add-ons)
(yum install jive-add-ons ~version)))
(install-jive 1.2)
我希望fn返回以下内容 -
(install-jive 1.2)=> “yum删除jive-add-ons; yum install jive-add-ons 1.2”
但目前它返回 -
“yum删除jive-add-ons; yum install jive-add-ons (clojure.core / unquote version)“
答案 0 :(得分:2)
您需要考虑需要生成宏的表单。例如,在您的情况下,您可能希望宏在扩展后生成类似的内容:
(defn install-jive [version]
(clojure.string/join
";"
[(clojure.string/join " " (list "yum" "remove" "jive-add-ons"))
(clojure.string/join " " (list "yum" "install" "jive-add-ons" version))]))
宏转换了String
列表中的前3个元素,但没有触及version
。这是一个用于表单的宏:
(defmacro single-cmd [cmd-form]
`(clojure.string/join " " (list ~@(map str (take 3 cmd-form))
~@(drop 3 cmd-form))))
扩展此宏会生成:
(macroexpand '(single-cmd (yum remove jive-add-ons version)))
=> (clojure.string/join " " (clojure.core/list "yum" "remove" "jive-add-ons" version))
(macroexpand '(single-cmd (yum remove)))
=> (clojure.string/join " " (clojure.core/list "yum" "remove"))
这是我们扩展到每个命令所需的内容。现在我们需要创建一个扩展它的宏:
(cmd
(yum remove jive-add-ons)
(yum install jive-add-ons version))
进入我们想要的形式。这是一个简单的版本,只是为了给你一个想法:
(defmacro cmd [& cmds]
`(clojure.string/join
";"
(list (single-cmd ~(first cmds))
(single-cmd ~(second cmds)))))
扩展它会产生:
(macroexpand '(cmd
(yum remove jive-add-ons)
(yum install jive-add-ons version)))
=> (clojure.string/join
";"
(clojure.core/list (user/single-cmd (yum remove jive-add-ons))
(user/single-cmd (yum install jive-add-ons version))))
现在:
(install-jive 1.2)
=> "yum remove jive-add-ons;yum install jive-add-ons 1.2"
我的版本做了两个大假设:前三个元素应该始终转换为String
,并且总是用两个命令调用cmd
。您可能需要改进它来解决您的问题。
但我认为这会让你在正确的方向上轻推一下。有一本很棒的书Mastering Clojure Macros可以帮助你发展你的宏技能。
答案 1 :(得分:1)
(defmacro cmd [& cmds]
`(join "; "
[~@(for [cmd cmds]
`(join " "
[~@(for [arg cmd]
(if (and (seq? arg) (= (first arg) 'clojure.core/unquote))
(second arg)
(list 'quote arg)))]))]))
如果您与原始代码进行比较,您会看到这一个延迟调用加入到运行时,并将非引号形式作为结果命令模板中的表达式。