2024 年 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());

这将给出类似以下错误消息

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

2 答案

0

评论者:alexmiller

有趣的是,实际上可以为 defmethods 分配名称,这些名称将包含在它们的类名中。defmethod 的 argslist 为:((link: multifn dispatch-val & fn-tail)),其中 fn-tail 是传递给 fn 的尾部参数,包括一个可选的名称。

因此,您可以这样做

`
(defmulti foo :class)
;; 创建具有名称 HI 的 defmethod
(定义方法 foo 对字符串 HI 执行 [x],抛出 (Exception. (str "hi " x))))

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

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

0
by
参考: https://clojure.atlassian.net/browse/CLJ-2263 (由 slipset 报告)
...