On Thu, Sep 15, 2011 at 8:56 AM, Herwig Hochleitner
<hhochleit...@gmail.com> wrote:
> Hi,
>
> as you might know, the original version actually does run in fixed
> stack space, thanks to lazy sequences.

You are right!

Without testing it I had thought that the way recursion was used would
cause skl to overflow the stack if the input tree was very deep on its
first elements.

> (defn skl
>  [tree]
>  (map skl (filter seq? tree)))

But in testing this skl fn I couldn't get it to overflow.  This is
because the tree is not flattened, and so calling 'first' on the top
level of the resulting tree only forces the top-level map, whose first
item remains a lazy seq, neatly avoiding an overflow error.

Good catch, Herwig!

> Consider
>
> (defn find-in-tree
>  ([tree pred?]
>    (concat
>      (filter pred? tree)
>      (mapcat find-in-tree (filter sequential? tree) (repeat pred?)))))
>
> which of course is much simpler written as
>
> (defn find-in-tree
>  ([tree pred?] (filter pred? (flatten tree))))
>
> all of which are lazy, hence consume constant stack space

Alas, this suffers from exactly the problem that I incorrectly
believed skl suffered from.  It works fine for some trees:

(find-in-tree (reduce list (range 1000)) #(when-not (seq? %) (even? %)))
;=> (0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44
46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90
92 94 96 98 100 102 104 106 108 110 112 114 116 118 120 122 124 126
128 130 132 134 136 138 140 142 144 146 148 150 152 154 156 158 160
162 164 166 168 170 172 174 176 178 180 182 184 186 188 190 192 194
196 198 200 202 204 ...)

But the lazy seqs form a chain so that in order to return the first
element of the result, they seqs must each force the next in the
chain, consuming call stack frames as they go.  Provide a tree deep
enough and it overflows the stack:

(find-in-tree (reduce list (range 10000)) #(when-not (seq? %) (even? %)))
; StackOverflowError   clojure.lang.RT.boundedLength (RT.java:1607)


Nevertheless let us now marvel for a moment at the beauty of lazy
seqs, that they can sometimes avoid both premature computation and
stack overflows, even in cases where no amount of
tail-call-optimization would help! And all this while delivering code
so similar to the problem statement and therefore concise, compared to
the long and tortured loop/recur version I posted yesterday.

--Chouser

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

Reply via email to