view src/rlm/function_utils.clj @ 1:8565803376a4

upgrading source to work with clojure 1.4
author Robert McIntyre <rlm@mit.edu>
date Tue, 28 Feb 2012 13:26:34 -0600
parents 78a630e650d2
children b8bbb0dbda7b
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 mix
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 mix-threads
27 ;; " Takes any number of pure functions that take the same arguments and
28 ;; compute the same value and returns a function that runs each in a separate
29 ;; thread, returns the result from the first thread which finshes, and cancels
30 ;; the other threads. Explicitly uses nasty Threads.
32 ;; For example:
33 ;; (do
34 ;; (defn fun1 [] (Thread/sleep 5000) 5)
35 ;; (defn fun2 [] (Thread/sleep 700000) 5)
36 ;; (time ((mix fun1 fun2))))
38 ;; Returns:
39 ;; | Elapsed time: 5000.66214 msecs
40 ;; 5"
41 ;; [& functions]
42 ;; (fn [& args]
43 ;; (let [result (prof :create-atom (atom void))
44 ;; threads
45 ;; (prof :create-threads (map
46 ;; (fn [fun]
47 ;; (Thread.
48 ;; (fn []
49 ;; (try (let [answer (apply fun args)]
50 ;; (reset! result answer))
51 ;; (catch Exception _ nil)))))
52 ;; functions))]
54 ;; (prof :start-threads (dorun (map #(.start %) threads)))
55 ;; (prof :loop (loop []
56 ;; (if (= (deref result) void)
57 ;; (recur)
58 ;; (do (prof :kill-threads (dorun (map #(.stop %) threads)))
59 ;; (prof :return (deref result)))))))))
61 (defmacro defmix
62 " Defines a function from any number of pure functions that take the same
63 arguments and compute the same value which:
65 Runs each in a separate thread.
66 Returns the result from the first thread which finshes.
67 Cancels the other threads.
69 Use this whenever you want to combine two pure functions that
70 compute the same thing, but use different algorithms with different
71 run times for various inputs.
73 For example:
74 (do
75 (defn fun1 [] (Thread/sleep 5000) 5)
76 (defn fun2 [] (Thread/sleep 700000) 5)
77 (defmix fun3 \"combination of fun1 and fun2\" fun1 fun2)
78 (time (fun3))
80 Returns:
81 | Elapsed time: 5000.66214 msecs
82 5"
84 {:arglists '([name doc-string? functions*])}
86 [name & functions]
87 (let [doc-string (if (string? (first functions)) (first functions) "")
88 functions (if (string? (first functions)) (rest functions) functions)
89 arglists (:arglists (meta (resolve (eval `(quote ~(first functions))))))
90 name (with-meta name
91 (assoc (meta name) :arglists `(quote ~arglists)
92 :doc doc-string))]
93 `(def ~name (mix ~@functions))))
95 (defn runonce
96 "Decorator. returns a function which will run only once. Inspired
97 by Halloway's version from lancet."
98 {:author "Robert McIntyre"}
99 [function]
100 (let [sentinel (Object.)
101 result (atom sentinel)]
102 (fn [& args]
103 (locking sentinel
104 (if (= @result sentinel)
105 (reset! result (apply function args))
106 @result)))))