Macros Clojure函数文字#(),明白了

Macros Clojure函数文字#(),明白了,macros,clojure,Macros,Clojure,我正在重构我的代码,使之更简单。演变过程是这样的,首先是: (defn board-changed "called when current-board changes" [fr _ _ _ _] (repaint! (select fr [:#canvas]))) 然后在另一个函数中: . . (add-watch the-board :board (partial board-changed fr)) . . 我决定我并不真正需要单独的函数,改变了board,我可以改

我正在重构我的代码,使之更简单。演变过程是这样的,首先是:

(defn board-changed
      "called when current-board changes"
  [fr _ _ _ _]
  (repaint! (select fr [:#canvas])))
然后在另一个函数中:

.
.
(add-watch the-board :board (partial board-changed fr))
.
.
我决定我并不真正需要单独的函数,改变了board,我可以改为以匿名方式内联定义它,在这个过程中,不再需要(部分),也不再需要每次查找画布,这导致了以下代码:

.
.
(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)))
.
.
它默默地失败了:第一次叫手表时,程序陷入了黑洞:没有错误或异常


出了什么问题?

我以前在传递无效参数时见过这样的行为:要么因为传递了意外类型而出现异常,要么传递了无效数量的参数(奇怪的是,这些参数似乎并不总是引发异常!)

这就是后者的一个例子:参数数量错误。但是为什么呢

我做的第一件事是宏扩展:

(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。(那些有趣的参数名是gensym)

所以我遇到的问题是,我传递给addwatch的函数必须正好有4个参数,但是由#()生成的函数取零

因此,结论是(fn arg list body)只能在body引用传入的最后一个参数时替换为#(body)

所以

可以用

#(println %4)
#(println "hello world")
但是

不可替代

#(println %4)
#(println "hello world")

我必须承认,我很惊讶你没有得到运行时算术异常

我以前在传递无效参数时见过这样的行为:要么因为传递了意外的类型而得到异常,要么因为传递了无效数量的参数(奇怪的是,似乎并不总是抛出异常!)

这就是后者的一个例子:参数数量错误。但是为什么呢

我做的第一件事是宏扩展:

(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。(那些有趣的参数名是gensym)

所以我遇到的问题是,我传递给addwatch的函数必须正好有4个参数,但是由#()生成的函数取零

因此,结论是(fn arg list body)只能在body引用传入的最后一个参数时替换为#(body)

所以

可以用

#(println %4)
#(println "hello world")
但是

不可替代

#(println %4)
#(println "hello world")
我必须承认,我很惊讶你没有得到运行时算术异常

这是。如果缓存了第一个故障,则下一个故障将立即发生

如果操作函数引发任何异常,则不会发生嵌套调度,并且异常将缓存在代理本身中。当代理缓存了错误时,任何后续交互都将立即抛出异常,直到代理的错误被清除。可以使用“代理错误”检查代理错误,并使用“重新启动代理”重新启动代理

您可以使用
代理错误
检查首次故障错误,或使用
设置错误处理程序注册错误处理程序


so.core=>(defa(代理0))
#“那么,core/a
so.core=>(添加watcha:key#(println“foo”))
#
so.core=>(设置错误处理程序!a(fn[代理异常](println“bar”))
无
so.core=>(发送一个inc)
#
酒吧
so.core=>(代理错误a)
#
so.core=>(发送一个inc)
算术例外
传递给以下对象的参数(4)数目错误:core/eval1299/fn--1300
clojure.lang.AFn.throwArity(AFn.java:429)
这是一个。如果缓存了第一个故障,则下一个故障将立即发生

如果操作函数引发任何异常,则不会发生嵌套调度,并且异常将缓存在代理本身中。当代理缓存了错误时,任何后续交互都将立即抛出异常,直到代理的错误被清除。可以使用“代理错误”检查代理错误,并使用“重新启动代理”重新启动代理

您可以使用
代理错误
检查首次故障错误,或使用
设置错误处理程序注册错误处理程序


so.core=>(defa(代理0))
#“那么,core/a
so.core=>(添加watcha:key#(println“foo”))
#
so.core=>(设置错误处理程序!a(fn[代理异常](println“bar”))
无
so.core=>(发送一个inc)
#
酒吧
so.core=>(代理错误a)
#
so.core=>(发送一个inc)
算术例外
传递给以下对象的参数(4)数目错误:core/eval1299/fn--1300
clojure.lang.AFn.throwArity(AFn.java:429)

addwatch
需要一个包含4个参数的函数。使用匿名函数literal
#(…)
而不使用参数literal,会使读取器生成一个没有参数的函数


为了节省空间,您可以编写
(fn[&!]…)

addwatch
需要4个参数的函数。使用匿名函数literal
#(…)
而不使用参数literal,会使读取器生成一个没有参数的函数


为了节省空间,您可以编写
(fn[&!]…)

谢谢!我怀疑这是因为它在代理功能中,但找不到任何细节。谢谢!我怀疑它