Hi all,

I've been trying to incorporate lazy seqs into my project, but kept
running into troubles where things were evaluated that I didn't think
should be.  After thinking a bit and looking into the Clojure source
for the first time, I think I've realized the source of the issue: the
empty seq == nil.  This means that every "lazy" function or macro that
returns a seq -- for, lazy-cat, filter, etc. -- must always do enough
pre-emptive evaluation to determine whether the return value should be
nil or an object.   So, my first question is, is this analysis
correct?  If not, please enlighten me (and either way, maybe consider
devoting a FAQ question to this...).

Now, assuming this is correct, my follow-up question is: why do things
this way (rather than using "empty?" to tell if a seq is empty, like a
collection)?  I'm very new to the community and don't mean to suggest
that I know better, I'm just curious about the rationale since I'm
sure it will shed more light on the language for me.

Finally, the workaround.  A little background: I was trying to build a
lazy stack data structure (where entire lazy seqs, incidentally
involving a filter or (for :when) could be pushed on the front), and
found that elements kept being unexpectedly evaluated.  In particular,
any element ever at the top of the stack was always evaluated, even if
it was never popped and was subsequently buried by other elements.
I wanted to avoid this extra evaluation, without introducing "delay"
and "force" everywhere, or writing my own versions of the built-in seq
functions.

To this end, I designed a new Java class that creates a truly lazy
*collection* from a seq-able expression.  Since collections don't have
the same contract as seqs, it does not need to preemptively evaluate
arguments to determine if it is empty, and won't do so until actually
needed (e.g., you call seq on the collection).  You can download the
Java class [1], and use it with the following Clojure wrapper:

(defmacro delay-seq "Create a collection representing this seq-able
expr, *really* without evaluating it until needed."
  [expr] `(DelayedSeq. (fn [] (seq ~expr))))

Then, if you want an operation to be *really* lazy, you just wrap it
with a call to delay-seq.  For instance, (delay-seq (concat .....))
will never evaluate the concat call until actually needed.  Note that
the result of delay-seq is a seq-able collection, and no corresponding
force call is ever needed.

[1] http://w01fe.com/?attachment_id=48

Comments about this are very welcome; this was my first voyage into
the internals of Clojure, and I still have lots to learn.

Cheers, Jason
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to