Mercurial > rlm
view src/rlm/function_utils.clj @ 6:b8bbb0dbda7b
merging
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Thu, 01 Mar 2012 05:55:59 -0700 |
parents | 12d1367cf1aa 8565803376a4 |
children | 1065e7d615a4 |
line wrap: on
line source
1 ;; Various Operators on Pure Functions2 ;;3 ;; Open source Liscence and all that4 (ns5 rlm.function-utils6 "Collection of Operators on Pure Functions"7 {:author "Robert McIntyre"})9 (def void ::void)11 (defn race12 "Takes any number of mathematically equal functions with13 possibly different run-times and returns a function that14 runs each in a separate thread, returns the result from15 the first thread which finishes, and cancels the other threads."16 {:author "Robert McIntyre"}17 ([& functions]18 (fn [& args]19 (let [result (promise)20 futures (doall (for [fun functions]21 (future (deliver result (apply fun args)))))22 answer @result]23 (dorun (map future-cancel futures))24 answer))))26 (defn race-pred27 "Takes any number of mathematically equal functions with possibly28 different run-times and returns a function that runs each in a29 separate thread, and returns the first available result x for30 which (pred x) returns true (or not-valid, if (pred x) returns31 false on all the results). Cancels the other threads upon32 returning early."33 {:author "Robert McIntyre"}34 ([pred not-valid & functions]35 (fn [& args]36 (let [result (promise)37 latch (java.util.concurrent.CountDownLatch.38 (count functions))39 failure-case (future (.await latch)40 (deliver result not-valid))41 futures42 (doall43 (cons failure-case44 (for [fun functions]45 (future46 (let [answer? (apply fun args)]47 (if (pred answer?)48 (deliver result answer?)49 (.countDown latch)))))))50 answer @result]51 (dorun (map future-cancel futures))52 answer))))54 (defmacro defmix55 " Defines a function from any number of pure functions that take the same56 arguments and compute the same value which:58 Runs each in a separate thread.59 Returns the result from the first thread which finshes.60 Cancels the other threads.62 Use this whenever you want to combine two pure functions that63 compute the same thing, but use different algorithms with different64 run times for various inputs.66 For example:67 (do68 (defn fun1 [] (Thread/sleep 5000) 5)69 (defn fun2 [] (Thread/sleep 700000) 5)70 (defmix fun3 \"combination of fun1 and fun2\" fun1 fun2)71 (time (fun3))73 Returns:74 | Elapsed time: 5000.66214 msecs75 5"77 {:arglists '([name doc-string? functions*])}79 [name & functions]80 (let [doc-string (if (string? (first functions)) (first functions) "")81 functions (if (string? (first functions)) (rest functions) functions)82 arglists (:arglists (meta (resolve (eval `(quote ~(first functions))))))83 name (with-meta name84 (assoc (meta name) :arglists `(quote ~arglists)85 :doc doc-string))]86 `(def ~name (mix ~@functions))))88 (defn runonce89 "Decorator. returns a function which will run only once. Inspired90 by Halloway's version from lancet."91 {:author "Robert McIntyre"}92 [function]93 (let [sentinel (Object.)94 result (atom sentinel)]95 (fn [& args]96 (locking sentinel97 (if (= @result sentinel)98 (reset! result (apply function args))99 @result)))))