On Jan 14, 2:57 pm, Rich Hickey <richhic...@gmail.com> wrote:
> On Jan 13, 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?
>
> It's hard to enumerate everything that is problematic with this
> approach to determining efficiency.
>
> Let's start with the basics:
>
> 1) Premature optimization is the root of all evil
> 2) See #1
> 3) You can't draw conclusions from a single execution of a short
> function
> 4) See #1
> 5) If you design with Delays etc to put off, avoid or cache a time-
> consuming computation, then test with trivial computations, you know
> nothing
> 6) See #1
> 7) timings that include I/O tend to be dominated by it
> 8) see #1
> ...
>

On rereading this I see #5 could be taken the wrong way - I mean you
learn nothing from that test, as the Delays/parallelization etc
dominate the time, when with a long computation they wouldn't.

Rich

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