2024 State of Clojure 问卷调查中分享您的想法!

欢迎!请参阅关于页面,了解更多关于这个工作原理的信息。

0投票
错误

09:43 $ clj
Clojure 1.8.0
(defmulti foo :bar)
(defmethod foo :qix [quux znoot] (println 'hi))
#'user/foo
user=> #object[clojure.lang.MultiFn 0x205d38da "clojure.lang.MultiFn@205d38da"]
user=> (foo {:bar :qix})
ArityException 错误参数数量(1)传递给:user/eval5/fn--6  clojure.lang.AFn.throwArity (AFn.java:429)
user=>


这是实现细节,多方法是通过匿名函数实现的。我期望错误信息至少包含失败的函数名称,在这种情况下,它应该是这样的:


ArityException 错误参数数量(1)传递给:user/eval5/foo--6  clojure.lang.AFn.throwArity (AFn.java:429)


可以采取几种方法来处理这里的情况

第一个(也是最简单的)是改变 {{defmethod}} 的定义,使得匿名函数有一个名称。
这导致了一个类似以下的错误信息

user=> (defmulti foo :bar)
(defmethod foo :qix [quux znoot] (println 'hi))
(foo {:bar :qix})#'user/foo
user=> #object[clojure.lang.MultiFn 0x4e928fbf "clojure.lang.MultiFn@4e928fbf"]
user=>
ArityException 错误参数数量(1)传递给:user/eval5/foo--6  clojure.lang.AFn.throwArity (AFn.java:429)
user=>

除此之外,还可以修改 Compiler.java 以查找对 "addMethod" 的调用

String prefix = "eval";
if (RT.count(form) > 2) {
   Object third = RT.nth(form, 2);
   if (third != null &&
       "clojure.core/addMethod".equals(third.toString())){
      prefix = "multi_fn";
}
ObjExpr fexpr = (ObjExpr) analyze(C.EXPRESSION, RT.list(FN, PersistentVector.EMPTY, form), prefix + RT.nextID());

}

which would give us error messages like

登录注册以回答此问题。

0投票
2 个回答

评论由:alexmiller 提供

有趣的是,实际上可以为defmethod命名,这些名称包含在其类名中。defmethod的arglist为:((link: multifn dispatch-val & fn-tail)),其中fn-tail是fn传递的尾参数,包括可选的名称。

所以你可以这样做

`
(defmulti foo class)
;; 创建具有名称HI的defmethod
(defmethod foo String HI [x] (throw (Exception. (str "hi " x)))))

;; 调用
(foo "bleh")
Exception hi bleh user/eval1248/HI--1249 (form-init1348837216879020682.clj:1)
`

注意类名中的HI。这不能解决所有问题,但它是一个有用的调试技巧。

0投票
by
...