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?


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