从Clojure开始,我发现了Rich Hickey的演讲,他在基础Ant-Simulator上展示了Clojure的一些优势。
此代码是否仍被视为Clojure的良好参考?特别是当他递归地向代理发送函数以模拟游戏循环时的部分。 例如:
(defn animation [x]
(when b/running
(send-off *agent* #'animation))
(. panel (repaint))
(. Thread (sleep defs/animation-sleep-ms))
nil)
修改
我对#'
读者宏并不感兴趣,但更多的是它是惯用的/好的Clojure
递归地调用代理上的函数。
答案 0 :(得分:3)
此片段在Clojure 1.4中是最新的。将函数提交回调用它的代理程序的函数是否惯用?是。
以下是使用类似方法递归计算阶乘的示例:
(defn fac [n limit total]
(if (< n limit)
(let [next-n (inc n)]
(send-off *agent* fac limit (* total next-n))
next-n)
total))
(def a (agent 1))
(await (send-off a fac 5 1))
; => nil
@a
;=> 120
<强>更新强>
上面是一个人为的例子,实际上并不是一个很好的例子,因为各种递归send-off
调用和后面的await
之间存在竞争条件。可能还有一些send-off
调用要添加到代理的任务队列中。
我重写了以上内容:
(defn factorial-using-agent-recursive [x]
(let [a (agent 1)]
(letfn [(calc [n limit total]
(if (< n limit)
(let [next-n (inc n)]
(send-off *agent* calc limit (* total next-n))
next-n)
total))]
(await (send-off a calc x 1)))
@a))
并观察到以下行为:
user=> (for [x (range 10)] (factorial-using-agent-recursive 5))
(2 4 3 120 2 120 120 120 120 2)
user=> (for [x (range 10)] (factorial-using-agent-recursive 5))
(2 2 2 3 2 2 3 2 120 2)
user=> (for [x (range 10)] (factorial-using-agent-recursive 5))
(120 120 120 120 120 120 120 120 120 120)
故事的道德是:不要使用代理进行同步计算。将它们用于异步独立任务 - 例如更新显示给用户的动画:)