このスニペットはClojure1.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)
話の教訓は次のとおりです。同期計算にエージェントを使用しないでください。ユーザーに表示されるアニメーションの更新など、非同期の独立したタスクに使用します:)