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

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