Sorry to resurrect this, but I noticed that there isn't an issue to track this - is this something unlikely to be fixed officially for 1.0 ? The workaround you posted certainly works for me, but I just wanted to make sure the actual core.clj filter implementation receives the fix eventually.
On Dec 8 2008, 6:51 pm, Rich Hickey <richhic...@gmail.com> wrote: > On Dec 8, 2008, at 8:56 PM, Stephen C. Gilardi wrote: > > > > > I think I finally see the problem. The "rest expression" infilter's > > call to lazy-cons has a reference to "coll" in it. That's all it > > takes for coll to be retained during the entire calculation of the > > rest. > > > (defnfilter > > "Returns a lazy seq of the items in coll for which > > (pred item) returns true. pred must be free of side-effects." > > [pred coll] > > (when (seq coll) > > (if (pred (first coll)) > > (lazy-cons (first coll) (filterpred (rest coll))) > > (recur pred (rest coll))))) > > > The stye of fix that occurs to me involves peeling off coll from > > (frest coll) and (rrest coll) before continuing the lazy evaluation. > > > Posting so someone else can beat me to the answer. :-) > > I'm sorry I haven't chimed in sooner. I fully understand this. Yes, > it's the closure over coll in the rest portion, which means that after > finding some match, a subsequent call to rest that needs to skip a lot > will create a window over the interval where the seq will be realized. > > Eagerly evaluating (rest coll) won't work - the result will still be > in the closure while the recursion occurs. The only solutions involve > mutation infilter. Here's one way: > > (defnfilter > [pred coll] > (let [sa (atom (seq coll)) > step (fn step [] > (when-let [s @sa] > (let [x (first s)] > (if (pred x) > (lazy-cons x (do (swap! sa rest) (step))) > (do (swap! sa rest) > (recur))))))] > (step))) > > But it's not pretty. Fortunately, this segues with work I have been > doing on I/O and generators/streams. This will let you write things > like: > > (defnfilter-stream > "Returns a stream of the items in strm for which > (pred item) returns true. pred must be free of side-effects." > [pred strm] > (stream > #(let [x (next! strm)] > (if (or (eos? x) (pred x)) x (recur))))) > > (defnfilter > "Returns a lazy seq of the items in coll for which > (pred item) returns true. pred must be free of side-effects." > [pred coll] > (stream-seq (filter-stream pred (stream coll)))) > > I'm still not done with this yet, so anyone who is stuck can use the > former version. > > 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 -~----------~----~----~----~------~----~------~--~---