On Dec 8, 2008, at 8:56 PM, Stephen C. Gilardi wrote:

> I think I finally see the problem. The "rest expression" in filter'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.
>
> (defn filter
>  "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) (filter pred (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 in filter. Here's one way:

(defn filter
   [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:

(defn filter-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)))))

(defn filter
    "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 [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to