Coming back to your helpful comments about relationship between acc-style 
and lazy...

It's worth understanding how to go back and forth between accumulator-style 
> and a lazy construction.  You can convert the above non-lazy accumulator 
> version into a similar version that is lazy but has no risk of stack 
> overflow in the realization of that lazy flattened list:
>

I notice in your lazy version (below), you preface the last cons with a 
lazy-seq call, but do not do the same with the other cons calls (within the 
first recur form).  I know it was only the last line that previously had a 
conj call and so participated in this transformation... but I'm wondering 
why you wouldn't also use lazy-seq with the other cons-involving line?

To answer my own wondering, I am thinking it is for two reasons:

   1. The main reason for using lazy-seq in the last line is to defer the 
   recursive call to my-flatten until something wants to use it.  In contrast, 
   the other cons-involving line only conses up things which are relatively 
   harmless to evaluate.
   2. The "cons (first x) ..." will be "undone" almost immediately after 
   the recur is executed, via the "(first xs)".  So inserting laziness here is 
   counter productive.

Another question...

I notice that you bound ys to (rest xs), in contrast to my choice of (next 
xs) in some of my implementations.  I realize this is probably a minor 
point, but just wondering whether (rest xs) was a deliberate choice of 
yours, or just habit.  I realize that rest maximizes laziness in contrast 
to next, but do we want maximum laziness here?

To again attempt to answer my own question...  It probably depends on what 
xs is being passed into my-flatten.  It xs is a fully realized sequence, 
then (next x) would probably do.  But if xs is itself lazy (and possibly 
expensive to compute), then using (rest x) maximizes our laziness 
opportunity.

Maybe the thing to do would be to use (next x) here for this 
implementation, which is angling to be lazy...  But in your earlier 
acc-based my-flatten, to use (next x) instead, because this implementation 
is eager and we know we're going to realize all of xs at some point anyway. 
 It this logic sound?  (I realize I am being pedantic, but I'm trying to 
understand the principles involved.)

Thanks again for showing me the relationship between acc-based and lazy - 
helpful!


> (defn my-flatten
>   [xs]
>   (if (empty? xs) ()
>     (let [x (first xs), ys (rest xs)]
>       (if (sequential? x)
>         (if (seq x)
>           (recur (cons (first x) (cons (rest x) ys)))
>           (recur ys))
>         (lazy-seq (cons x (my-flatten ys)))))))
>
> Basically, you just get rid of the accumulator, and in the place where you 
> would have conj'd in the next atomic element, you just build the lazy 
> sequence.
>
>

-- 
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
Note that posts from new members are moderated - please be patient with your 
first post.
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to