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
-~----------~----~----~----~------~----~------~--~---

Reply via email to