diff 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 diff
     1.1 --- a/src/rlm/function_utils.clj	Tue Oct 18 00:57:08 2011 -0700
     1.2 +++ b/src/rlm/function_utils.clj	Tue Feb 28 13:26:34 2012 -0600
     1.3 @@ -4,67 +4,10 @@
     1.4  (ns 
     1.5      rlm.function-utils
     1.6    "Collection of Operators on Pure Functions"
     1.7 -  {:author "Robert McIntyre"}
     1.8 -  (:use [clojure.contrib.profile]))
     1.9 +  {:author "Robert McIntyre"})
    1.10  
    1.11  (def void ::void)
    1.12  
    1.13 -(comment
    1.14 -
    1.15 -  "Please help me out here.  I'm trying to make a higher order function that takes
    1.16 -   pure functions that are mathmaticaly the same but have different times and returns another
    1.17 -   function that runs them both and returns the resut of the one that finishes first."
    1.18 -
    1.19 -
    1.20 -  "here's a repl session:
    1.21 -
    1.22 -mobius> " (time (dotimes [_ 500]((mix-futures + +) 40 3 3 3 3 3))) "
    1.23 -Elapsed time: 85.792995 msecs
    1.24 -nil
    1.25 -mobius> " (time (dotimes [_ 500](+ 40 3 3 3 3 3))) "
    1.26 -Elapsed time: 6.956338 msecs
    1.27 -nil
    1.28 -mobius> " (time (dotimes [_ 500]((mix-threads + +) 40 3 3 3 3 3))) "
    1.29 -Elapsed time: 706.227065 msecs
    1.30 -nil
    1.31 -
    1.32 -
    1.33 -mobius> " (defn fast-five [& args] 5) "
    1.34 -#'mobius/fast-five
    1.35 -
    1.36 -mobius> " (defn slow-five [& args] (Thread/sleep 5000) (println "Oh YEAH!!!!") 5) "
    1.37 -#'mobius/slow-five
    1.38 -
    1.39 -mobius> " (profile (time (dotimes [_ 5000] (thread-five)))) "
    1.40 -\"Elapsed time: 12187.981587 msecs\"
    1.41 -          Name      mean       min       max     count       sum
    1.42 -   create-atom      9621      2025   4433928      5000  48106830
    1.43 -create-threads      5156      2724   2880268      5000  25783796
    1.44 -  kill-threads     91313     27866  11175718      5000  456567066
    1.45 -          loop   2124249     38482  18470781      5000  10621249899
    1.46 -        return      1242       838      5309      5000   6212626
    1.47 - start-threads    252985    110348  12272835      5000  1264927953
    1.48 -nil
    1.49 -
    1.50 -mobius> " (profile (time (dotimes [_ 5000] (future-five)))) "
    1.51 -\"Elapsed time: 607.266671 msecs\"
    1.52 -          Name      mean       min       max     count       sum
    1.53 -   create-atom      1472      1047     31708      5000   7363139
    1.54 -create-futures     30539      2514   1330660      5000  152697998
    1.55 -  kill-threads     54158      2444   3938833      5000  270792897
    1.56 -          loop     81117      8800   6083059      5000  405587516
    1.57 -        return      1215       838    618782      5000   6078146
    1.58 -nil
    1.59 -
    1.60 -
    1.61 -
    1.62 -What can I improve here, and why is the future version sooo much faster than the
    1.63 -thread version? Is there a better way than using loop?
    1.64 -"
    1.65 -
    1.66 -)
    1.67 -
    1.68 -
    1.69  (defn mix 
    1.70    "Takes any number of mathematically equal functions with
    1.71     possibly different run-times and returns a function that
    1.72 @@ -80,44 +23,40 @@
    1.73  	 (dorun (map future-cancel futures))
    1.74  	 answer))))
    1.75  
    1.76 +;; (defn mix-threads
    1.77 +;;   " Takes any number of pure functions that take the same arguments and
    1.78 +;;    compute the same value and returns a function that runs each in a separate
    1.79 +;;    thread, returns the result from the first thread which finshes, and cancels 
    1.80 +;;    the other threads. Explicitly uses nasty Threads.
    1.81  
    1.82 -
    1.83 -
    1.84 -(defn mix-threads
    1.85 -  " Takes any number of pure functions that take the same arguments and
    1.86 -   compute the same value and returns a function that runs each in a separate
    1.87 -   thread, returns the result from the first thread which finshes, and cancels 
    1.88 -   the other threads. Explicitly uses nasty Threads.
    1.89 -
    1.90 -   For example: 
    1.91 -   (do
    1.92 -   (defn fun1 [] (Thread/sleep 5000) 5)
    1.93 -   (defn fun2 [] (Thread/sleep 700000) 5)
    1.94 -   (time ((mix fun1 fun2))))
    1.95 +;;    For example: 
    1.96 +;;    (do
    1.97 +;;    (defn fun1 [] (Thread/sleep 5000) 5)
    1.98 +;;    (defn fun2 [] (Thread/sleep 700000) 5)
    1.99 +;;    (time ((mix fun1 fun2))))
   1.100     
   1.101 -   Returns: 
   1.102 -    | Elapsed time: 5000.66214 msecs
   1.103 -   5"
   1.104 -  [& functions]
   1.105 -  (fn [& args]
   1.106 -    (let [result (prof :create-atom (atom void))
   1.107 -	  threads
   1.108 -	   (prof :create-threads (map 
   1.109 -	   (fn [fun] 
   1.110 -	     (Thread. 
   1.111 -	      (fn [] 
   1.112 -		(try (let [answer (apply fun args)]
   1.113 -		       (reset! result answer))
   1.114 -		     (catch Exception _ nil)))))
   1.115 -	   functions))]
   1.116 +;;    Returns: 
   1.117 +;;     | Elapsed time: 5000.66214 msecs
   1.118 +;;    5"
   1.119 +;;   [& functions]
   1.120 +;;   (fn [& args]
   1.121 +;;     (let [result (prof :create-atom (atom void))
   1.122 +;; 	  threads
   1.123 +;; 	   (prof :create-threads (map 
   1.124 +;; 	   (fn [fun] 
   1.125 +;; 	     (Thread. 
   1.126 +;; 	      (fn [] 
   1.127 +;; 		(try (let [answer (apply fun args)]
   1.128 +;; 		       (reset! result answer))
   1.129 +;; 		     (catch Exception _ nil)))))
   1.130 +;; 	   functions))]
   1.131        
   1.132 -      (prof :start-threads (dorun (map #(.start %) threads)))
   1.133 -      (prof :loop (loop []
   1.134 -	(if (=  (deref result) void)
   1.135 -	  (recur)
   1.136 -	  (do (prof :kill-threads (dorun (map #(.stop %) threads)))
   1.137 -	      (prof :return (deref result)))
   1.138 -	  ))))))
   1.139 +;;       (prof :start-threads (dorun (map #(.start %) threads)))
   1.140 +;;       (prof :loop (loop []
   1.141 +;; 	(if (=  (deref result) void)
   1.142 +;; 	  (recur)
   1.143 +;; 	  (do (prof :kill-threads (dorun (map #(.stop %) threads)))
   1.144 +;; 	      (prof :return (deref result)))))))))
   1.145  
   1.146  (defmacro defmix
   1.147    " Defines a function from any number of pure functions that take the same 
   1.148 @@ -148,10 +87,11 @@
   1.149    (let [doc-string (if (string? (first functions)) (first functions) "")
   1.150  	functions (if (string? (first functions)) (rest functions) functions)
   1.151  	arglists (:arglists (meta (resolve (eval `(quote ~(first functions))))))
   1.152 -	name (with-meta name (assoc (meta name) :arglists `(quote ~arglists) :doc doc-string))]   
   1.153 +	name (with-meta name
   1.154 +               (assoc (meta name) :arglists `(quote ~arglists)
   1.155 +                      :doc doc-string))]   
   1.156      `(def ~name (mix ~@functions))))
   1.157  
   1.158 -
   1.159  (defn runonce
   1.160    "Decorator.  returns a function which will run only once. Inspired
   1.161     by Halloway's version from lancet."
   1.162 @@ -165,21 +105,3 @@
   1.163  	   (reset! result (apply function args)) 
   1.164  	    @result)))))
   1.165  
   1.166 -
   1.167 -
   1.168 -;I'm thinking this will be the docstring for mix eventually.
   1.169 -
   1.170 -  ;; " Takes any number of pure functions that take the same arguments and
   1.171 -  ;;  compute the same value and returns a function that runs each in a separate
   1.172 -  ;;  thread, returns the result from the first thread which finshes, and cancels 
   1.173 -  ;;  the other threads.
   1.174 -
   1.175 -  ;;  For example: 
   1.176 -  ;;  (do
   1.177 -  ;;  (defn fun1 [] (Thread/sleep 5000) 5)
   1.178 -  ;;  (defn fun2 [] (Thread/sleep 700000) 5)
   1.179 -  ;;  (time ((mix fun1 fun2))))
   1.180 -   
   1.181 -  ;;  Returns: 
   1.182 -  ;;   | Elapsed time: 5000.66214 msecs
   1.183 -  ;;  5"