clojure - 传递给宏时评估 arg

标签 clojure

我有一个小宏,它接受一系列 cmd 作为 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 remove jive-add-ons; yum install jive-add-ons 1.2"

但是目前它返回 -

"yum remove jive-add-ons; yum install jive-add-ons (clojure.core/unquote version)"

最佳答案

您需要考虑需要宏生成什么表单。例如,在您的情况下,您可能希望宏在扩展后生成如下所示的内容:

(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))]))

该宏将列表中的前 3 个元素转换为 String 形式,并且没有触及 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这可以帮助您培养宏技能。

关于clojure - 传递给宏时评估 arg,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28539980/

相关文章:

clojure - 根据数据类型格式化输出字符串

clojure - 分离 map 的多个后代键?

clojure - 尝试 'group' 并展平 clojure 中嵌套结构的值

Clojure:将 HashMap 键字符串转换为关键字?

clojure - 如何在 Clojure 的函数/宏内的另一个命名空间中定义变量?

java - 初始化 Java 对象的 Clojure 惯用方法

scala - 如何访问 Scala REPL 中的最后结果?

angularjs - Cemerick Friend 和单页应用程序

具有多个调度值的 Clojure 多方法

mongodb - 自动将 Mongodb ObjectId 映射到字符串和从字符串映射