arityException,其arity为(-1)

时间:2015-01-29 22:21:19

标签: debugging macros clojure

有一个宏,我一直试图将此错误计算出来ArityException Wrong number of args (-1) passed to: user/bar clojure.lang.Compiler.macroexpand1 (Compiler.java:6557)。我试图调试但我不明白为什么当我尝试扩展宏时,为什么有(-1)的arity。

我正在运行以下代码。

(defn foo [x] (println x))

(defmacro bar [exp]
  (let [length (count exp)]
    (cond
      (= length 0) '()
      (= length 1) exp
      :else (let [[head & tail] (vec exp)
                  [new-tail] (bar tail)]
        `(trap (~head ~@new-tail))))))

(macroexpand '(bar (inc 1)))

任何人都知道(-1)的arity发生了什么?

1 个答案:

答案 0 :(得分:2)

使用REPL中的*e var我打印了堆栈跟踪。

clojure.lang.ArityException: Wrong number of args (-1) passed to: user/bar
                                Compiler.java:6557 clojure.lang.Compiler.macroexpand1
                                     core.clj:3703 clojure.core/macroexpand-1
                                     core.clj:3712 clojure.core/macroexpand

这指向Compiler.java中的clojure.lang.Compiler.macroexpand1方法,我找到了这一行:

throw new ArityException(e.actual - 2, e.name);

如果e.actual1,则-1构造函数的第一个参数的结果为ArityException。有一个JIRA票here提到这个非常令人困惑的ArityException消息。

根据此故障单的说法,我开始在其他地方寻找ArityException,并在使用countvec时发现它,好像exp始终如此一个列表。

问题在于,当递归地调用宏bar时,参数实际上是符号 tail,它不是一个集合,而这个调用实际上是宏扩展的调用宏本身时会创建

更改宏的代码以便它考虑非列表的可能值可以解决问题,但我认为生成的宏不能满足您的需求。

(defmacro bar' [exp]
  (prn exp)
  (let [length (if (seq? exp) (count exp) 0)]
    (cond
      (= length 0) '()
      (= length 1) exp
      :else 
      (let [[head & tail] (if (seq? exp) (vec exp) [exp])
            [new-tail] (bar' tail)]
        `(trap (~head ~@new-tail))))))
;; tail

(macroexpand '(bar' (inc 1)))
;; (inc 1)
;;= (user/trap (inc))