Hello Luke,
One thing that might would out well for you is that Clojure
supports lazy evaluation of sequences.
Consider a scenario where we want to do a "big-computation" (1 sec
each)
on records in a list with a billion items. Typically we don't
may not need all the billion items processed (we may need only
a filtered subset for e.g.).
I have a little function (free-mem) defined below.
(defn free-mem [] (.. Runtime (getRuntime) (freeMemory)))
Here is a simple test at REPL:
user=> (free-mem)
2789176
user=> (defn big-computation [x] (. Thread sleep 1000) (* 10 x))
#'user/big-computation
user=> (time (big-computation 1))
"Elapsed time: 1001.760391 msecs"
10
Ok. So we have big-computation that runs for 1 sec.
user=> (time (def nums (range 1000000000)))
"Elapsed time: 0.166994 msecs"
#'user/nums
Note that it takes me only 0.17 ms to create a list of 1billion
numbers. This is because the list is not really created. I just
have the promise of a list.
Now we take item x from 10000 to 10005 and apply big-computation
to it.
user=> (time (def v (apply vector
(map big-computation
(take 5
(filter (fn [x]
(and (> x 10000) (< x
10010)))
nums))))))
"Elapsed time: 5089.247035 msecs"
#'user/v
Here we create an anonymous function fn that gives us a list
of x from 10000 to 10010. Note that these are 10 items, not 5.
And yet, our time was just 5 seconds (and not 10 seconds for
10 items). This is because we just took 5 items "(take 5 ...)"
from this filtered list of 10 so the remaining computation for
5 items was never done.
Now if we access v it takes negelegible time.
user=> (time (seq v))
"Elapsed time: 0.047423 msecs"
(100010 100020 100030 100040 100050)
Note that the amount of free memory is more or less the same.
user=> (free-mem)
2732024
user=>
Another point to note that a lazy sequence does not mean that
the computation is done every time, so once the computation is
done, it gets cached.
Try the following:
user=> (time (def comps (map big-computation nums)))
"Elapsed time: 0.113774 msecs"
#'user/comps
user=> (defn t5 [] (take 5 comps))
#'user/t5
user=> (t5) ; this will take 5 seconds
(0 10 20 30 40)
user=> (t5) ; this will take 0 seconds as the seq
(0 10 20 30 40) ; will not be evaluated again.
Basically, IMHO lazy data structures can offer significant
advantage assuming that your program is designed to leverage
that. This is probably a paradigm shift from just "doing
the computation" in languages like C and Java vs
"giving a promise of a computation".
Have a look at:
http://en.wikibooks.org/wiki/Clojure_Programming#Lazy_Evaluation_and_Infinite_Data_Source
also see take and variant along with filter, map and for on
Clojure page.
Sequences:
http://clojure.org/sequences
API :
http://clojure.org/api
My recommendation would be to give it a shot. It might be
worth it. If you feel otherwise you always have the option
of dropping into Java as Clojure has good Java interop.
Hope this helps.
Parth