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