6

Starting with Clojure I discovered a talk by Rich Hickey where he demonstrates some of Clojure's strengths on a basic Ant-Simulator.

Can this code still be considered as a good reference for Clojure? Especially the parts when he recursively sends off functions to agents to simulate a game loop. Example:

(defn animation [x] (when b/running (send-off *agent* #'animation)) (. panel (repaint)) (. Thread (sleep defs/animation-sleep-ms)) nil) 

Edit:

I am not interested in the #' reader macro but more wether it is idiomatic/good Clojure to recursively call a function on a agent or not.

3
  • What specific code snipped can you post so a problem can be stated, so we can help you? Otherwise, I'm thinking this question belongs over on Programmers. Commented Sep 3, 2012 at 15:45
  • Why is the #' reader macro needed when recursively sending animation to *agent*? Commented Sep 3, 2012 at 16:14
  • 2
    This evaluates animation every time it is used. This way animationcan be changed on the fly Commented Sep 3, 2012 at 18:14

1 Answer 1

3

This snippet is current in Clojure 1.4. Is it idiomatic for a function to submit a task back to the agent that called it? Yes.

Here is an example that uses a similar approach to recursively calculate a factorial:

(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 

Update

The above is a contrived example and actually not a good one, as there is a race condition between the various recursive send-off calls and the later await. There may be some send-off calls yet to be added to the agent's task queue.

I re-wrote the above as follows:

(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)) 

and observed the following behavior:

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) 

Moral of the story is: don't use agents for synchronous calculations. Use them for asynchronous independent tasks - like updating animations displayed to a user :)

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.