annotate 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
rev   line source
rlm@0 1 ;; Various Operators on Pure Functions
rlm@0 2 ;;
rlm@0 3 ;; Open source Liscence and all that
rlm@0 4 (ns
rlm@0 5 rlm.function-utils
rlm@0 6 "Collection of Operators on Pure Functions"
rlm@1 7 {:author "Robert McIntyre"})
rlm@0 8
rlm@0 9 (def void ::void)
rlm@0 10
rlm@6 11 (defn race
rlm@0 12 "Takes any number of mathematically equal functions with
rlm@0 13 possibly different run-times and returns a function that
rlm@0 14 runs each in a separate thread, returns the result from
rlm@0 15 the first thread which finishes, and cancels the other threads."
rlm@0 16 {:author "Robert McIntyre"}
rlm@0 17 ([& functions]
rlm@0 18 (fn [& args]
rlm@0 19 (let [result (promise)
rlm@0 20 futures (doall (for [fun functions]
rlm@0 21 (future (deliver result (apply fun args)))))
rlm@0 22 answer @result]
rlm@0 23 (dorun (map future-cancel futures))
rlm@0 24 answer))))
rlm@0 25
rlm@4 26 (defn race-pred
rlm@4 27 "Takes any number of mathematically equal functions with possibly
rlm@4 28 different run-times and returns a function that runs each in a
rlm@4 29 separate thread, and returns the first available result x for
rlm@4 30 which (pred x) returns true (or not-valid, if (pred x) returns
rlm@4 31 false on all the results). Cancels the other threads upon
rlm@4 32 returning early."
rlm@3 33 {:author "Robert McIntyre"}
rlm@4 34 ([pred not-valid & functions]
rlm@3 35 (fn [& args]
rlm@3 36 (let [result (promise)
rlm@4 37 latch (java.util.concurrent.CountDownLatch.
rlm@4 38 (count functions))
rlm@4 39 failure-case (future (.await latch)
rlm@4 40 (deliver result not-valid))
rlm@4 41 futures
rlm@4 42 (doall
rlm@4 43 (cons failure-case
rlm@4 44 (for [fun functions]
rlm@4 45 (future
rlm@4 46 (let [answer? (apply fun args)]
rlm@4 47 (if (pred answer?)
rlm@4 48 (deliver result answer?)
rlm@4 49 (.countDown latch)))))))
rlm@3 50 answer @result]
rlm@3 51 (dorun (map future-cancel futures))
rlm@3 52 answer))))
rlm@0 53
rlm@0 54 (defmacro defmix
rlm@0 55 " Defines a function from any number of pure functions that take the same
rlm@0 56 arguments and compute the same value which:
rlm@0 57
rlm@0 58 Runs each in a separate thread.
rlm@0 59 Returns the result from the first thread which finshes.
rlm@0 60 Cancels the other threads.
rlm@0 61
rlm@0 62 Use this whenever you want to combine two pure functions that
rlm@0 63 compute the same thing, but use different algorithms with different
rlm@0 64 run times for various inputs.
rlm@0 65
rlm@0 66 For example:
rlm@0 67 (do
rlm@0 68 (defn fun1 [] (Thread/sleep 5000) 5)
rlm@0 69 (defn fun2 [] (Thread/sleep 700000) 5)
rlm@0 70 (defmix fun3 \"combination of fun1 and fun2\" fun1 fun2)
rlm@0 71 (time (fun3))
rlm@0 72
rlm@0 73 Returns:
rlm@0 74 | Elapsed time: 5000.66214 msecs
rlm@0 75 5"
rlm@0 76
rlm@0 77 {:arglists '([name doc-string? functions*])}
rlm@0 78
rlm@0 79 [name & functions]
rlm@0 80 (let [doc-string (if (string? (first functions)) (first functions) "")
rlm@0 81 functions (if (string? (first functions)) (rest functions) functions)
rlm@0 82 arglists (:arglists (meta (resolve (eval `(quote ~(first functions))))))
rlm@1 83 name (with-meta name
rlm@1 84 (assoc (meta name) :arglists `(quote ~arglists)
rlm@1 85 :doc doc-string))]
rlm@0 86 `(def ~name (mix ~@functions))))
rlm@0 87
rlm@0 88 (defn runonce
rlm@0 89 "Decorator. returns a function which will run only once. Inspired
rlm@0 90 by Halloway's version from lancet."
rlm@0 91 {:author "Robert McIntyre"}
rlm@0 92 [function]
rlm@0 93 (let [sentinel (Object.)
rlm@0 94 result (atom sentinel)]
rlm@0 95 (fn [& args]
rlm@0 96 (locking sentinel
rlm@0 97 (if (= @result sentinel)
rlm@0 98 (reset! result (apply function args))
rlm@0 99 @result)))))
rlm@0 100