我正在重构我的代码以使其更简单。这种演变是这样的,从以下开始:
(defn board-changed
"called when current-board changes"
[fr _ _ _ _]
(repaint! (select fr [:#canvas])))
然后在另一个函数中:
.
.
(add-watch the-board :board (partial board-changed fr))
.
.
我决定我并不真的需要一个单独的功能,更换板,我可以在内联中匿名定义它,并在此过程中删除(部分)的需要,并且不需要每次都查找画布时间,这导致了这段代码:
.
.
(let [cnv (select fr [:#canvas])]
(add-watch the-board :board (fn [_ _ _ _] (repaint! cnv))))
.
.
此代码有效。
我决定下一步是使用#()宏进一步简化,但我发现下面的代码不起作用:
.
.
(let [cnv (select fr [:#canvas])]
(add-watch the-board :board #(repaint! cnv)))
.
.
它默默地失败:第一次调用手表时程序会掉入黑洞:没有错误或例外。
出了什么问题?
答案 0 :(得分:3)
这是how agent errors work。你第一次失败是缓存,下一次会立即发生。
如果动作函数抛出任何异常,则不会发生嵌套调度,并且异常将缓存在代理本身中。当代理程序缓存了错误时,任何后续交互都将立即引发异常,直到代理程序的错误被清除。可以使用代理错误检查代理错误,并使用restart-agent重新启动代理。
您可以使用agent-error
检查首次失败错误,或使用set-error-handler!
so.core=> (def a (agent 0))
#'so.core/a
so.core=> (add-watch a :key #(println "foo"))
#<Agent@766245a4: 0>
so.core=> (set-error-handler! a (fn [the-agent the-exception] (println "bar")))
nil
so.core=> (send a inc)
#<Agent@766245a4: 1>
bar
so.core=> (agent-error a)
#<ArityException clojure.lang.ArityException:
Wrong number of args (4) passed to: core/eval1299/fn--1300>
so.core=> (send a inc)
ArityException
Wrong number of args (4) passed to: core/eval1299/fn--1300
clojure.lang.AFn.throwArity (AFn.java:429)
答案 1 :(得分:3)
add-watch
需要4个参数的函数。使用不带参数文字的匿名函数文字#(...)
会使读者产生一个无参数的函数。
为节省空间,您可以撰写(fn [& _] ...)
。
答案 2 :(得分:1)
我在传递无效参数之前就已经看到过这样的行为了:你要么得到一个例外,因为你传递了一个意想不到的类型,或者你传递了一个无效的数字参数(奇怪的是,似乎并不总是抛出异常!)。
事实证明这是后者的一个例子:错误的参数数量。但为什么呢?
我做的第一件事是宏扩展:
(clojure.pprint/pprint (macroexpand '#(repaint! cnv)))
=> (fn* [] (repaint! cnv))
这给了我第一个线索:我在函数参数中假设#()灵活性,在运行时提供了将它们称为%,%1,%2等的能力。
宏观扩展下面的表格确认了它:
(clojure.pprint/pprint (macroexpand '(add-watch the-board :board #(repaint! %4))))
=> (fn* [p1__7764# p2__7765# p3__7766# p4__7763#] (repaint! p4__7763#))
#()查看具有最高编号的%的正文,在本例中为4,并假设该函数有很多参数,因此在这种情况下为4.(那些有趣的参数名称是gensyms)。 / p>
所以我遇到的问题是我传递给add-watch的函数必须使用4个参数,但#()生成的函数为零。
所以结论是(fn arg-list body)只能在主体引用传入的最后一个参数时用#(body)替换。
所以
(fn [_ _ _ arg4] (println arg4))
可以替换为
#(println %4)
但是
(fn [_ _ _ _] (println "hello world")
无法替换
#(println "hello world")
我必须承认,我很惊讶您没有获得运行时间异常!