You should be able to do this without the ref. Have the agent's state contain a pair of [has-run, fn-result].
Stuart > Hi, > > Am 09.11.2008 um 12:23 schrieb Stuart Halloway: >> Just to make things even more fun: *None* of the proposed fixes to >> the >> concurrency bug in the original actually preserve the` semantics of >> the original. All have moved from "run (usually) once, mark as done" >> to "mark as done, try once". This also means that other threads could >> see a runonce as being done when it hasn't begun yet. > > Hmm.. I have no clue about concurrent programming whatsoever. But > for such cases, maybe an agent would do the trick. Send it the action. > The first time it runs, it calls the function and caches the result. > This could be done maybe with delay/force. Multiple sends would be > automatically be syncronised. But to get the result out of the agent > one would have to pass in a ref, where the results are stored. > > (defmacro defrunonce > [n & body] > `(def ~n > (let [agent# (agent (delay [EMAIL PROTECTED])) > retr# (fn [state# r-ref#] > (let [r# (force state#)] > (dosync (ref-set r-ref# r#))))] > (fn [] > (let [r-ref# (ref nil)] > (send agent# retr# r-ref#) > (await agent#) > (deref r-ref#)))))) > > user=> (defrunonce foo (println :Run) 5) > #=(var user/foo) > user=> (foo) > :Run > 5 > user=> (foo) > 5 > > Ok. Maybe this is also only a hack. > > Sincerely > Meikel > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---
