On Sat, Feb 28, 2009 at 6:09 AM, Rich Hickey <richhic...@gmail.com> wrote:
> I think your fundamental hangup is on looking at (rest x) as a
> calculation/effect triggered by a consumer. (rest x) is logically just
> a slot lookup that obtains another seq. The laziness of that seq is
> its constructor's problem.

Right, I'm aware that "rest" isn't an expensive operation.  This was
meant to be for illustrative purposes.

In my actual code, it's more like this:

Imagine a permutation algorithm that works by storing the sequence in
a vector, and then permuting the various indices to get new sequences.
 Simplifying considerably, with no laziness, the heart might look kind
of like this:

(defn permutation-helper [v indices]
  (cons (vector-in-order-of-indices v indices)
     (permutations v
(do-complicated-transformation-of-indices-to-next-permutation
indices))))

So where should the lazy-seq call go?

(defn permutation-helper [v indices]
  (lazy-seq (cons (vector-in-order-of-indices v indices)
     (permutations v
(do-complicated-transformation-of-indices-to-next-permutation
indices)))))

unnecessarily does the complicated-transform function when you call first.

(defn permutation-helper [v indices]
  (cons (vector-in-order-of-indices v indices)
     (lazy-seq (permutations v
(do-complicated-transformation-of-indices-to-next-permutation
indices)))))

works better for this case, but unnecessarily does the
vector-in-order-of-indices at the beginning, and whenever you call
rest (not a hugely expensive operation, but let's pretend it is).

(defn permutation-helper [v indices]
  (lazy-seq (cons (vector-in-order-of-indices v indices)
     (lazy-seq (permutations v
(do-complicated-transformation-of-indices-to-next-permutation
indices))))))

delays everything, but with a whole lot of overhead.

When you have a lot of local definitions that compute things before
the first call, and the helper function is embedded in something else,
deciding where to put lazy-seq becomes even more complicated.

For the most part, I decided the odd-style worked best, and went with
something like this:
(defn permutation-helper [v indices]
  (cons (vector-in-order-of-indices v indices)
     (lazy-seq (permutations v
(do-complicated-transformation-of-indices-to-next-permutation
indices)))))

(defn permutation [sequence]
  (lazy-seq (permutation-helper (vec sequence) (initialize-indices)))

thus delaying the setup and first element of the list, as well as all
the rests.  This is all just pseudo-code and not the actual thing, but
it's enough to convey the idea.

My point is that lazy-seq gives you a lot more choices than lazy-cons,
but isolating the expensive part, rather than just blindly choosing
even laziness (which is the paradigm it's mainly geared for), can be
complicated.  As I mentioned, rewriting filter to delay the call to
rest is an interesting exercise to see the challenge involved
(although I acknowledge that delaying rest isn't inherently useful
given that, like you said, sequence providers will ensure that.rest is
fast).

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