在Clojure中是否存在多个arity函数超过1个可变参数的多变量函数的变通方法?

时间:2016-03-17 05:06:28

标签: clojure macros

我创建了一个宏,其定义如下:

(defmacro my-macro
  [strategy & body] 
   ...)

您可以像这样调用此宏:

(my-macro {:strategy "some"}
       (do-something ..))

现在,我希望宏可选接受绑定。像这样:

(my-macro [my-value (load-value ..)]
       {:strategy my-value}
       (do-something ..))

所以我尝试将宏扩展为这样:

(defmacro my-macro
  ([strategy & body] `(my-macro [] ~routes ~body))
  ([bindings strategy & body] 
    ...))

但这失败了:

java.lang.RuntimeException: Can't have more than 1 variadic overload

是否有一种很好的方法可以解决这个或推荐的方法?

2 个答案:

答案 0 :(得分:3)

我的典型解决方法是检查传递给my-macro的整个参数列表,并决定是否使用绑定:

(defmacro my-macro
  [& body]
  (let [bindings (if (vector? (first body)) (first body) [])
        [strategy body*] (if (seq bindings) (rest body) body)]
    `(let ~bindings
       (do-something-with ~body* ~strategy))))

答案 1 :(得分:2)

我会提出这个:

(defmacro my-macro
  {:arglists '([bindings? strategy & body])}
  [bindings-or-strategy & more-args]
    (let [[bindings strategy body] (if (vector? bindings-or-strategy)
                                     [bindings-or-strategy
                                      (first more-args)
                                      (rest more-args)]
                                     [[] bindings-or-strategy more-args])]
      `(let ~bindings
         (println :strategy ~strategy)
         ~@body)))

user> (my-macro [a 1] {:aaa :bbb} a)
:strategy {:aaa :bbb}
1
user> (my-macro {:aaa :bbb} 10)
:strategy {:aaa :bbb}
10

虽然它看起来比@ superkonduktr的答案更冗长,但对我来说它似乎更有用:它确保至少传递一个参数,并用:arglists

记录这个宏的用法