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 Functions
2 ;;
3 ;; Open source Liscence and all that
4 (ns
5 rlm.function-utils
6 "Collection of Operators on Pure Functions"
7 {:author "Robert McIntyre"})
9 (def void ::void)
11 (defn race
12 "Takes any number of mathematically equal functions with
13 possibly different run-times and returns a function that
14 runs each in a separate thread, returns the result from
15 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-pred
27 "Takes any number of mathematically equal functions with possibly
28 different run-times and returns a function that runs each in a
29 separate thread, and returns the first available result x for
30 which (pred x) returns true (or not-valid, if (pred x) returns
31 false on all the results). Cancels the other threads upon
32 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 futures
42 (doall
43 (cons failure-case
44 (for [fun functions]
45 (future
46 (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 defmix
55 " Defines a function from any number of pure functions that take the same
56 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 that
63 compute the same thing, but use different algorithms with different
64 run times for various inputs.
66 For example:
67 (do
68 (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 msecs
75 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 name
84 (assoc (meta name) :arglists `(quote ~arglists)
85 :doc doc-string))]
86 `(def ~name (mix ~@functions))))
88 (defn runonce
89 "Decorator. returns a function which will run only once. Inspired
90 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 sentinel
97 (if (= @result sentinel)
98 (reset! result (apply function args))
99 @result)))))