Re: clojure.zip: skip a node

2018-03-06 Thread Marco Rucci
Hi all, thank for the helpful discussion.
I've stumbled upon the same issue of needing to skip a subtree during a 
traversal and solved it with the following skip function that is a slight 
modification of one in the original message:

(defn skip-subtree
  "Fast-forward a zipper to skip the subtree at `loc`."
  [loc]
  (cond
(zip/end? loc) loc
(some? (zip/right loc)) (zip/right loc)
(some? (zip/up loc)) (recur (zip/up loc))
:else (assoc loc 1 :end)))

In short, we traverse to the right if there's a right, otherwise we 
recursively go up and check again if there's a right.  If we never find a 
right, then we'll navigate back up to the root.  In this case, mark the 
zipper as consumed (with `:end`) and return.
Seems to be working well, so hopefully it can help somebody else. 

Cheers.

--
Marco


On Tuesday, May 6, 2014 at 5:24:53 PM UTC+2, Pascal Germroth wrote:
>
>
> On Tuesday, May 6, 2014 4:07:11 PM UTC+1, Alex Miller wrote:
>>
>> I wrote this article long ago which hints about this at the end:
>> https://www.ibm.com/developerworks/library/j-treevisit/
>>
>
> I started from that actually, very helpful article.
>
> I have since noticed a bug in my previous skip function where it would 
> loop infinitely when skipping from the rightmost location.
> The fix includes an end function, so I can no just iterate backwards using 
> that as you suggested.
>
> Leaving this here for future reference, in case anybody comes across the 
> same problem:
>
> (defn end
>   "returns the location loc where (end? (next loc)) is true."
>   [loc]
>   (loop [loc loc]
> (let [loc (z/rightmost loc)]
>   (if (z/branch? loc)
> (recur (z/down loc))
> loc
>
> (defn skip
>   "returns the next location that is not a child of this one"
>   [start-loc]
>   (loop [loc start-loc]
> (cond
>   ; can't skip, jump to end
>   (nil? loc) (z/next (end start-loc))
>   ; at end
>   (z/end? loc) loc
>   ; go to right/up
>   true (or (z/right loc)
>(recur (z/up loc))
>  
>
>>
>> The approach I have taken for editing trees with zippers is to do a 
>> post-walk from end to beginning - that way you're always done transforming 
>> and will not walk into your edited subtrees. The article does talk a little 
>> about how to separate navigation from transformation; it's not particularly 
>> hard. You want to start from your rightmost node, which you can get from a 
>> repeated application of zip/rightmost or last of zip/rights. Then 
>> repeatedly call prev till you reach a node without a parent at that point 
>> convert the loc to a node in the termination.
>>
>> I can dig up actual code for this later if you're interested.
>>
>> Alex
>>
>>
>> On Monday, May 5, 2014 6:01:04 PM UTC-5, Pascal Germroth wrote:
>>>
>>> Hi,
>>>
>>> I'm using clojure.zip to edit a tree by visiting each location using 
>>> zip/next, possibly using zip/replace to alter the tree.
>>> There are cases where I replace a part of the tree with another tree 
>>> that will/must not be visited, but I couldn't find a good way to skip 
>>> nodes, since
>>> (zip/next (zip/replace loc new-subtree)) will walk right into my new 
>>> tree, and I can't use (zip/right (zip/replace loc new-subtree)) as the 
>>> replaced location might already be the rightmost.
>>>
>>> Is there a built-in function I missed, or a zip enhancement library I 
>>> could use?
>>>
>>> (defn skip
>>>   "returns the next location that is not a child of this one"
>>>   [loc]
>>>   (if (or (z/end? loc) (nil? loc))
>>> loc
>>> (loop [loc loc]
>>>   (or (z/right loc)
>>>   (recur (z/up loc))
>>>
>>> I came up with this replacement, does that seem like a good idea, or am 
>>> I using zip completely wrong (because what I really would like to do is 
>>> iterate backwards through the tree, starting at the end, using zip/prev; 
>>> but there's also no function to just jump to the end as far as I can tell)
>>>
>>>
>>> Cheers,
>>>
>>> -- 
>>> pascal
>>>
>>

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


Re: clojure.zip: skip a node

2014-05-06 Thread Pascal Germroth

On Tuesday, May 6, 2014 4:07:11 PM UTC+1, Alex Miller wrote:
>
> I wrote this article long ago which hints about this at the end:
> https://www.ibm.com/developerworks/library/j-treevisit/
>

I started from that actually, very helpful article.

I have since noticed a bug in my previous skip function where it would loop 
infinitely when skipping from the rightmost location.
The fix includes an end function, so I can no just iterate backwards using 
that as you suggested.

Leaving this here for future reference, in case anybody comes across the 
same problem:

(defn end
  "returns the location loc where (end? (next loc)) is true."
  [loc]
  (loop [loc loc]
(let [loc (z/rightmost loc)]
  (if (z/branch? loc)
(recur (z/down loc))
loc

(defn skip
  "returns the next location that is not a child of this one"
  [start-loc]
  (loop [loc start-loc]
(cond
  ; can't skip, jump to end
  (nil? loc) (z/next (end start-loc))
  ; at end
  (z/end? loc) loc
  ; go to right/up
  true (or (z/right loc)
   (recur (z/up loc))
 

>
> The approach I have taken for editing trees with zippers is to do a 
> post-walk from end to beginning - that way you're always done transforming 
> and will not walk into your edited subtrees. The article does talk a little 
> about how to separate navigation from transformation; it's not particularly 
> hard. You want to start from your rightmost node, which you can get from a 
> repeated application of zip/rightmost or last of zip/rights. Then 
> repeatedly call prev till you reach a node without a parent at that point 
> convert the loc to a node in the termination.
>
> I can dig up actual code for this later if you're interested.
>
> Alex
>
>
> On Monday, May 5, 2014 6:01:04 PM UTC-5, Pascal Germroth wrote:
>>
>> Hi,
>>
>> I'm using clojure.zip to edit a tree by visiting each location using 
>> zip/next, possibly using zip/replace to alter the tree.
>> There are cases where I replace a part of the tree with another tree that 
>> will/must not be visited, but I couldn't find a good way to skip nodes, 
>> since
>> (zip/next (zip/replace loc new-subtree)) will walk right into my new 
>> tree, and I can't use (zip/right (zip/replace loc new-subtree)) as the 
>> replaced location might already be the rightmost.
>>
>> Is there a built-in function I missed, or a zip enhancement library I 
>> could use?
>>
>> (defn skip
>>   "returns the next location that is not a child of this one"
>>   [loc]
>>   (if (or (z/end? loc) (nil? loc))
>> loc
>> (loop [loc loc]
>>   (or (z/right loc)
>>   (recur (z/up loc))
>>
>> I came up with this replacement, does that seem like a good idea, or am I 
>> using zip completely wrong (because what I really would like to do is 
>> iterate backwards through the tree, starting at the end, using zip/prev; 
>> but there's also no function to just jump to the end as far as I can tell)
>>
>>
>> Cheers,
>>
>> -- 
>> pascal
>>
>

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


Re: clojure.zip: skip a node

2014-05-06 Thread Alex Miller
I wrote this article long ago which hints about this at the end:
https://www.ibm.com/developerworks/library/j-treevisit/

The approach I have taken for editing trees with zippers is to do a 
post-walk from end to beginning - that way you're always done transforming 
and will not walk into your edited subtrees. The article does talk a little 
about how to separate navigation from transformation; it's not particularly 
hard. You want to start from your rightmost node, which you can get from a 
repeated application of zip/rightmost or last of zip/rights. Then 
repeatedly call prev till you reach a node without a parent at that point 
convert the loc to a node in the termination.

I can dig up actual code for this later if you're interested.

Alex


On Monday, May 5, 2014 6:01:04 PM UTC-5, Pascal Germroth wrote:
>
> Hi,
>
> I'm using clojure.zip to edit a tree by visiting each location using 
> zip/next, possibly using zip/replace to alter the tree.
> There are cases where I replace a part of the tree with another tree that 
> will/must not be visited, but I couldn't find a good way to skip nodes, 
> since
> (zip/next (zip/replace loc new-subtree)) will walk right into my new tree, 
> and I can't use (zip/right (zip/replace loc new-subtree)) as the replaced 
> location might already be the rightmost.
>
> Is there a built-in function I missed, or a zip enhancement library I 
> could use?
>
> (defn skip
>   "returns the next location that is not a child of this one"
>   [loc]
>   (if (or (z/end? loc) (nil? loc))
> loc
> (loop [loc loc]
>   (or (z/right loc)
>   (recur (z/up loc))
>
> I came up with this replacement, does that seem like a good idea, or am I 
> using zip completely wrong (because what I really would like to do is 
> iterate backwards through the tree, starting at the end, using zip/prev; 
> but there's also no function to just jump to the end as far as I can tell)
>
>
> Cheers,
>
> -- 
> pascal
>

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


clojure.zip: skip a node

2014-05-05 Thread Pascal Germroth
Hi,

I'm using clojure.zip to edit a tree by visiting each location using 
zip/next, possibly using zip/replace to alter the tree.
There are cases where I replace a part of the tree with another tree that 
will/must not be visited, but I couldn't find a good way to skip nodes, 
since
(zip/next (zip/replace loc new-subtree)) will walk right into my new tree, 
and I can't use (zip/right (zip/replace loc new-subtree)) as the replaced 
location might already be the rightmost.

Is there a built-in function I missed, or a zip enhancement library I could 
use?

(defn skip
  "returns the next location that is not a child of this one"
  [loc]
  (if (or (z/end? loc) (nil? loc))
loc
(loop [loc loc]
  (or (z/right loc)
  (recur (z/up loc))

I came up with this replacement, does that seem like a good idea, or am I 
using zip completely wrong (because what I really would like to do is 
iterate backwards through the tree, starting at the end, using zip/prev; 
but there's also no function to just jump to the end as far as I can tell)


Cheers,

-- 
pascal

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