How about: (defn runonce "Create a function that will only run its argument once." [function] (let [call-count (ref 0)] (fn [& args] (when (= 1 (dosync (alter call-count inc))) (apply function args)))))
> On Nov 8, 2008, at 8:31 PM, Stuart Halloway wrote: > >> >> The defrunonce macro below works, creating a function that runs only >> once and tracking its run status in metadata. >> >> Now, how do I write it without using eval? >> >> (defn runonce >> "Create a function that will only run once, given a function. >> Returns >> a vector containing the function and the reference that tracks >> whether >> the function has been run." >> [function] >> (let [has-run (ref false)] >> [(fn [& args] >> (or @has-run >> ; TODO: think through semantics for parallel target invocation >> (do >> (apply function args) >> (dosync (ref-set has-run true))))) >> has-run])) > > Since the deref of has-run is outside a transaction, I don't see > anything here that prevents two threads from running function if > they're trying to do it at roughly the same time. > > I think the following version accomplishes the core task of running > just once and could be adapted to return the has-run ref as well: > > (defn runonce > "Create a function that will only run its argument once." > [function] > (let [has-run (ref false)] > (fn [& args] > (when > (dosync > (ensure has-run) > (when-not @has-run > (ref-set has-run true))) > (apply function args))))) > > I'd appreciate seeing corrections or simplifications of it. > > --Steve > > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com 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 -~----------~----~----~----~------~----~------~--~---