如何编写一个宏可以接受哪个是符号的参数

时间:2015-05-17 18:39:39

标签: clojure macros

我想写一个宏来接受一个向量参数

(defmacro eval-verify [body]
  `(cond
     ~@body
     :default nil))

在这种情况下适用

(eval-verify [true 1 false 2])

它返回1,我运行

(macroexpand-1 '(eval-verify [true 1 false 2]))

它返回

(clojure.core/cond true 1 false 2 :default nil)

看起来没问题,但是当我确定一个向量时

(def a [true 1 false 2])

并运行

(eval-verify a)

是错误

IllegalArgumentException Don't know how to create ISeq from: clojure.lang.Symbol

如何编写宏可以接受符号的参数,或写函数可以做同样的事情。

1 个答案:

答案 0 :(得分:4)

宏参数作为未评估的符号传递。因此,当您调用(eval-verify a) 符号时,a是传递给eval-verify而不是[true 1 false 2]的body参数的值。由于unquote-splice(〜@)需要Seq并且它找到符号(a),因此会收到IllegalArgumentException。

您需要使用(eval-verify [true 1 false 2])形式调用eval-verify,否则您需要使用普通函数。

您可以使用以下功能代替宏:

(defn eval-verify [coll]
  (loop [[f v :as c] coll]
    (cond
      (and (ifn? f) (f)) v
      (and (not (ifn? f)) f) v
      :else (if (seq c) (recur (drop 2 c)) nil))))