On Tue, Jan 13, 2009 at 12:39 PM, samppi <rbysam...@gmail.com> wrote: > > Recently, I asked how to make a function evaluate its arguments lazily > (http://groups.google.com/group/clojure/browse_thread/thread/ > cd01ef39c2b62530), and I was given a good solution: use Delay objects > (with the delay and force functions). > > I wanted to do this for the efficiency of a functional parser library > that uses many meta-functions and meta-meta-functions: I thought that > stopping arguments from being evaluated until needed was a good way to > prevent useless creation of objects, especially in huge trees of meta- > meta-functions. But I was very surprised when running my library's > unit tests to see that using Delay objects took much more time to run > the tests than not using Delays. Here's an example in a REPL: > > Clojure > user=> (defn alt [& functions] > (fn [tokens] > (some #(% tokens) functions))) > #'user/alt > user=> (defn sub-function1 [c] (println "1:" c) (fn [c] false)) > #'user/sub-function1 > user=> (defn sub-function2 [c] (println "2:" c) (fn [c] true)) > #'user/sub-function2 > user=> (defn sub-function3 [c] (println "3:" c) (fn [c] false)) > #'user/sub-function3 > user=> (defn a-meta-meta-function [c] > (alt (sub-function1 c) (sub-function2 c) (sub-function3 c))) > #'user/a-meta-meta-function > user=> (time ((a-meta-meta-function "CONTEXT") [:a :b :c])) > 1: CONTEXT > 2: CONTEXT > 3: CONTEXT > "Elapsed time: 1.018 msecs" > true > > ...vs... > > Clojure > user=> (defn alt [& functions] > (fn [tokens] > (some #((force %) tokens) functions))) > #'user/alt > user=> (defn sub-function1 [c] (println "1:" c) (delay (fn [c] > false)))) > #'user/sub-function1 > user=> java.lang.Exception: Unmatched delimiter: ) > user=> (defn sub-function1 [c] (println "1:" c) (delay (fn [c] > false))) > #'user/sub-function1 > user=> (defn sub-function2 [c] (println "2:" c) (delay (fn [c] true))) > #'user/sub-function2 > user=> (defn sub-function3 [c] (println "3:" c) (delay (fn [c] > false))) > #'user/sub-function3 > user=> (defn a-meta-meta-function [c] > (alt (sub-function1 c) (sub-function2 c) (sub-function3 c))) > #'user/a-meta-meta-function > user=> (time ((a-meta-meta-function foo) some-tokens)) > java.lang.Exception: Unable to resolve symbol: foo in this context > (NO_SOURCE_FILE:13) > user=> (time ((a-meta-meta-function "CONTEXT") [:a :b :c])) > 1: CONTEXT > 2: CONTEXT > 3: CONTEXT > "Elapsed time: 2.443 msecs" > true > > Why would it take so much more time? Is it because it might take a > long time to construct a Delay object? Can I do something different to > make it more efficient, or should I just not use Delay objects?
I wouldn't really expect that delay/force would be faster unless there are cases where the delay never gets forced. And of course then you'll only get savings in the event that the time it takes to execute the delayed expression would take longer than the creation of the delayed expression in the first place. In your expample it appears to me that all of the delays are being forced, and so I'm not surprised the runtime is longer. So overall, it does not seem unexpected that delay/force takes longer than the same raw expression. The real question is whether or not you'll end up with a lot of delay objects that never get forced--enough to justify the cost of creating the objects in the first place. /mike. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---