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 [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
-~----------~----~----~----~------~----~------~--~---