Re: Why does unquote clone values?

2014-07-04 Thread Pascal Germroth
Hi Atamert,

I'm not an expert but I believe REPL does compile the forms you enter to 
 bytecode. It compiles an fn form into a JVM class that implements IFn. It 
 also compiles a quoted form (such as `(fn ...) ) but this time it takes the 
 form of a list (as in (list ...) ), IOW it's still data after it is 
 compiled. The latter is executed directly and the former is evaluated 
 (turned into bytecode and then executed perhaps).


So I tried what I probably should have tried in the first place and used 
the debugger.
I think I understand what's going on now.

user= [(Object.)]
works: [#Object@...]

user= (eval `[ ~(Object.) ])
doesn't: CompilerException java.lang.RuntimeException: Can't embed object 
in code, maybe print-dup not defined

It begins by calling clojure.lang.Compiler.analyze on the list
(fn* [] (eval (clojure.core/apply clojure.core/vector (clojure.core/seq 
(clojure.core/concat (clojure.core/list (Object.)))
Recursively going through the expression and building up a tree of 
ConstantExpr, ending up with a
Compiler$FNExpr, that is actually compiled to Bytecode, it calls .eval() on 
this which returns an IFn (which is an instance of the dynamically-created 
class) and calls .invoke() on that.
We end up with an FNExpr with src= the list (that inner vector holds an 
actual reference to the Object, no strings anywhere)
(fn* [] [#Object java.lang.Object@4b2e26cf])
The error occurs when compiling this to Bytecode, specifically in:
emitValue( value = #Object java.lang.Object@4b2e26cf ... )
That method explicitly handles emitting bytecode that sits in the static 
constructor of the IFn for null and constants of type Boolean etc ... ISeq, 
IPersistentList and Pattern.
For all other types it calls RT.printString(value), trying to emit that 
string as a constant, to be interpreted by readString.
As the error message says printString fails for Object.

So it's not at all like I suspected:
- the unquoting doesn't clone anything, it simply the value in the list.
- eval doesn't roundtrip the entire form to String and back.

Eval clones everything because you can't embed a pointer to an existing 
object as a constant in Bytecode.
The reason the closure doesn't need to do element-wise comparison in my 
example is because the pointer to the existing object is passed as a 
constructor parameter at runtime.
f4 is so much slower than f1 despite apparently having the same bytecode is 
that the constructor for f1 is called with a pointer to the original 
object, while the constructor to f4 is called inside the eval, with a 
pointer to a clone of the object.

As far as I can tell AOT goes through the same steps and then just saves 
the generated bytecode in a .class file.
There appears to never be any kind of interpretation, it's always 
generating bytecode and having the JVM evaluate that, even for the most 
trivial expressions like (inc 1).

Sorry for spreading my confusion about this; probably would have been 
better suited as a blog post.

-- 
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: Why does unquote clone values?

2014-07-03 Thread Pascal Germroth
Hi Atamert,

Here's a gist with the example code: 
https://gist.github.com/neapel/4e502a14e3738b709672

I tried replacing a closure with a dynamically built and evaluated 
 metafunction but discovered that it was actually slower.


 If evaluating code during run is slower than AOT compiling it, it wouldn't 
 surprise me.


I didn't actually try AOT compiling it, just using the REPL. As far as I 
understand there shouldn't be a difference in speed, since (eval) runs the 
same compiler as AOT does, and even writes out a .class file.

(possibly unrelated, maybe due to eval, when trying to AOT compile the 
example project by adding `:aot :all` and running `lein jar`, it appears to 
fall into an infinite loop. The JAR file grew to 8GB, but I couldn't list 
its contents.)
 

 I guess f2 runs this much slower than f1 because it doesn't actually pass 
 a reference to x when unquoting, but clones the value, which means it needs 
 to compare the lists element-wise.


 This is interesting. Were you able to confirm it or are you just guessing? 
 (I'm just curious.) 


 The code in the Gist produces a nice table now, here's my result (I 
couldn't reproduce the case where f3 runs as fast as f1 for vectors; but 
it's actually less weird this way)
I think it's quite obvious that f1 compares always references, as does the 
nil case, while the vec and map cases compare by value:

|map |vec |  nil | name |
|++--+--|
|   5 ns |   5 ns | 5 ns |   f1 |
| 558 ns | 134 ns | 6 ns |   f2 |
| 567 ns | 130 ns | 7 ns |   f3 |
| 561 ns | 117 ns | 7 ns |   f4 |

It also dumps the disassembly, we can see that:

f1-map == f1-vec == f1-nil (makes sense, as the reference to the value is 
passed in the constructor of the closure)
f2-map = f3-map, f2-vec = f3-vec, f2-nil = f3-nil (with renaming)
f4-map = f1, f4-vec = f1, f4-nil = f1 (with renaming)
f2-map = f2-vec, except for calling clojure.lang.RT.map / vector.

So there are only three versions of the actual bytecode:
- the closure f1/f4;
- f2 building a new object in its static constructor
- f2-nil using a null constant instead of a field containing null.

importantly, f1/f4 are identical:
public final class F extends clojure.lang.AFunction {
  /* ... static constructor getting clojure.core/= ... */
  Object x;
  public F(Object o) { x = o }
  public Object invoke( Object y ) {
/*basically*/ return (bool (= x y))
  }
}

So why does f4 behave almost like f2/f3?!


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: Why does unquote clone values?

2014-07-03 Thread Pascal Germroth


On Thursday, July 3, 2014 5:19:56 PM UTC+1, adrian...@mail.yu.edu wrote:

 You're going down a rabbit hole here. Evaluating forms at runtime will 
 always result in a slower execution time than a function that doesn't 
 evaluate a form at runtime. 


I thought that was the whole point of Clojure?

The REPL is just parsing a string or file and running (eval) on it, I can't 
detect any difference in speed when doing it manually:

(quick-bench ((fn fac [x] (if (zero? x) 1 (* x (fac (dec x) 10)) ; = 
263 ± 9 ns
(eval `(quick-bench ((fn fac# [x#] (if (zero? x#) 1 (* x# (fac# (dec 
x#) 10))) ; 269 ± 8 ns

I'm very sure that the differences I measured are only because the lists 
are being copied instead of passed by reference, which I can understand in 
the case where the disassembly actually shows a copy being constructed. But 
not in the case where the bytecode is exactly the same --- and criterium 
takes a lot of time to warm up etc, all of the same optimisations should 
have been applied (and the dynamic part of the code is not a lot anyway, 
it's just calling AOT-compiled java code anyway. The only difference in 
timing must stem from the element-wise comparison)

-- 
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: Why does unquote clone values?

2014-07-03 Thread Pascal Germroth
On Thursday, July 3, 2014 6:15:32 PM UTC+1, adrian...@mail.yu.edu wrote:

 I'm not sure I understand what you're saying here. :( Your example is 
 simply benchmarking the same bit of code in each form. Why would evaluating 
 one explicitly affect that benchmark? Your original example called eval in 
 the body of the functions that you're benchmarking. That is where the 
 overhead comes from. 


No I'm benchmarking the functions returned by f1-4.
They use different ways of generating their return function, i.e. by 
eval'ing the function constructor (fn [] ...) once before the benchmark -- 
the `let [f (f1 v)]` part.
Of course the call to (eval) takes time, but my point is that a function 
that was generated using (eval) is exactly the same as one generated 
statically.

Except somehow when unquoting the x-parameter to create the eval'ed form 
things are being cloned that shouldn't. That's what I'm measuring.

Actually I just found a better example that doesn't need timing etc:

(def x (Object.))
(str x) ; java.lang.Object@...
`(str ~x) ; (clojure.core/str #Object java.lang.Object@...)
(eval `(str ~x)) ; RuntimeException: Can't embed object in code, maybe 
print-dup not defined: java.lang.Object@...
(eval `(str x)) ; java.lang.Object@... -- works through resolving user/x

So it's not actually a problem with quoting, that returns a list with str 
and the object as expected.
But eval'ing that list fails because it can't print-dup'ed?! I can't tell 
where that's happening, because it looks like clojure.lang.Parser.eval is 
actually processing the elements of the list as I expected…



-- 
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: Why does unquote clone values?

2014-07-03 Thread Pascal Germroth
On Thursday, July 3, 2014 7:27:24 PM UTC+1, adrian...@mail.yu.edu wrote:

 No I'm benchmarking the functions returned by f1-4. 

 Where did I say different? 


I understood Your original example called eval in the body of the 
functions that you're benchmarking as meaning I was running something like
(quick-bench (eval `( (fn [y] ...)  v)  ))
or
(quick-bench ( (eval `(fn [y] ...))  v)  )
But I'm actually calling eval before the benchmark and storing the output:
(let [f (eval `(fn [y] ...))] (quick-bench (f v)))
So the body that's being benchmarked is only the call to the dynamically 
generated function.
Unless I'm totally misunderstanding how Clojure evaluates these things 
[wouldn't surprise me].
 

 I would really like to help you gain a greater understanding here, but I 
 must admit you are coming off as fairly confrontational, so I am hesitant 
 to continue this conversation. Good luck. 


Sorry, that wasn't my intention. I kept repeating myself because I'm not 
sure if I'd be understood (since I'm new to Clojure and don't know the 
canonical words).
Also, there are a lot of other discussions where people use eval in tight 
loops and wonder why it's so slow; that and the mention of a difference 
between AOT and eval performance made me think I should make it clear that 
I'm not wondering why eval is slow, but why it's product behaves 
differently.
Using a benchmark to do so was way too indirect anyway, I believe my 
problem may have something to do with the failure of
(eval `(str ~(Object.)))

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.


Why does unquote clone values?

2014-07-02 Thread Pascal Germroth
Hi,

I tried replacing a closure with a dynamically built and evaluated 
metafunction but discovered that it was actually slower.
Here's a minimal example:

(defn f1 [x](fn [y ] (=x  y )))
(defn f2 [x] (eval `(fn [y#] (=   ~x  y#
(defn f3 [x] (eval `(fn [y#] (= ~@[x] y#

(use 'criterium.core)

(def v nil) ; nil - same speed.
(let [f (f1 v)] (quick-bench (f v))) ;  7.1ns
(let [f (f2 v)] (quick-bench (f v))) ;  5.4ns
(let [f (f3 v)] (quick-bench (f v))) ;  5.4ns

(def v [10 20]) ; vector - f2 slower
(let [f (f1 v)] (quick-bench (f v))) ;  6.8ns
(let [f (f2 v)] (quick-bench (f v))) ; 78.0ns
(let [f (f3 v)] (quick-bench (f v))) ;  5.3ns

(def v {10 20}) ; map - f2 and f3 slower?!
(let [f (f1 v)] (quick-bench (f v))) ;   6.6ns
(let [f (f2 v)] (quick-bench (f v))) ; 151.0ns
(let [f (f3 v)] (quick-bench (f v))) ; 152.0ns

I guess f2 runs this much slower than f1 because it doesn't actually pass a 
reference to x when unquoting, but clones the value, which means it needs 
to compare the lists element-wise. The other cases all compare the 
references which is why the nil case runs at the same speed.

Why does unquoting ~x clone the vector?
And why doesn't splice unquoting ~@[x] appear to clone the vector, but 
*does* clone the map?!

Is there a way to pass all values per reference into a quote, to get 
exactly the same behaviour as f1?


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: Why does unquote clone values?

2014-07-02 Thread Pascal Germroth
It gets even weirder. I tried this hoping it would create a closure like f1 
does:

(defn f4 [x] (eval `(let [[x#] ~@[[x]]]
  (fn [y#]
(= x# y#)

And indeed using no.disassemble in my test cases f1 and f4 always create 
the same bytecode: a clojure.lang.AFunction with a field holding the value 
x, which is passed through the function's constructor.
Likewise, f2 and f3 always create the same bytecode: an AFunction without 
any fields and an empty constructor, with a static constructor creating a 
new vector/map/nil.

All the bodies are identical, calling clojure.lang.Util.equiv, with the 
argument and the stored reference object.

(now talking about the functions returned by f1-4)
But: in the vector case, f4 takes 140ns, almost twice of what even f2 
takes, and much longer than f1 (which is apparently identical!).
It makes no sense that f3 (identical to f2) doesn't take that long.

In the map case, f2, f3 and f4 take the same time, 150ns, again making no 
sense as f1=f4.

Is there some metadata I'm missing?

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


How to debug redefinitions of classes

2014-06-26 Thread Pascal Germroth
Hi,

I'm observing an incredibly weird bug in my program where this happens on 
the REPL

(use 'myapp.some.stuff)
(def x (-Record 1))
(type x) ; = myapp.some.stuff.Record
(instance? myapp.some.stuff.Record x) ; = false
(instance? (type x) x) ; = true

Somewhere the namespace gets reloaded, and there actually exist two classes 
called Record, with the same name, in the same namespace, and the -Record 
constructor uses one version, but the REPL resolves another version. Is 
there any way I can tell how this came about?

Another example, where the problem is more obvious:

(defrecord Foo [x]) ; = user.Foo
(def f1 (-Foo 1))
(defrecord Foo [x]) ; = user.Foo
(def f2 (-Foo 2))
(type f1) ; = user.Foo
(type f2) ; = user.Foo
(= user.Foo (type f1)) ; = false
(= user.Foo (type f2)) ; = true
(instance? Foo f1) ; = false
(instance? Foo f2) ; = true

Foo on the REPL resolves to the second version, but f1 still uses the 
first, which still claims to be named the same.
This makes things very hard to debug, when i.e. hot reloading some code and 
see things break in mysterious ways.
Usually things resolve themselves when restarting the app, taking care to 
only load each namespace once, but I somehow created a situation where this 
doesn't help either.

When duplicating classes by reloading code, all metadata is identical, i.e. 
source location etc; except if you aquire a pointer to the old version of 
the class instance it's not identical to the new version.

Ideally I'd like some kind of *warn-on-redefinition* flag that prints a 
stacktrace which lead to a class being redefined over an existing one.

I tried adding a check to a custom version of defrecord:

(defmacro defrecord*
  [name  args]
  (let [ns-part (namespace-munge *ns*)
classname (symbol (str ns-part . name))]
(try (resolve classname)
 ; exists: fail.
 (throw (IllegalArgumentException. (str Will not redefine  
classname)))
 (catch ClassNotFoundException e
   ; doesn't exist: go ahead.
   `(let []
  ; as before
  (defrecord ~name ~@args)
  ; name?
  (defn ~(symbol (str name '?))
[x#] (instance? ~classname x#))
  ; return class
  ~classname)

But this causes all attempts to load the code to fail, (use 
'myapp.some.stuff) now always throws the Will not redefine exception, 
even in a fresh REPL.
For some reason everything appears to be loaded twice -- I thought using 
(ns .. (:require [...])) made sure to only load the namespace if it isn't 
already loaded, I'm not using :reload / :force-reload?!
And (use 'myapp.some.stuff :verbose) only logs a single clojure.core/load 
as expected; the error is actually thrown after loading clojure.zip?! I 
assume it's because the compiler runs in a separate thread from the loader?

(clojure.core/load /clojure/zip)

CompilerException java.lang.IllegalArgumentException: Will not redefine...



TL;DR are there more tracing options to figure out what is being 
(re-)loaded?


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.


Find source/location of anonymous function by name

2014-05-10 Thread Pascal Germroth
Hi,

Say I'm getting an ArityException Wrong number of args (2) passed to: 
myparser/fn--106751 exception.
Unfortunately the code is quite heavy on the higher order side, so the 
stack trace doesn't reveal anything useful, especially since the exception 
is thrown by the `apply` before, so I'm not even getting line number 
information. And I don't really want to read a mile of traces or step 
through every call of `apply`.

Is there a direct way to get the source location information, like the 
stack-trace-printer seems to do, just from the generated name of a closure 
like myparser/fn--106751? It's not defined as a var, so (source) doesn't 
work.


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: Find source/location of anonymous function by name

2014-05-10 Thread Pascal Germroth
On 10 May 2014, at 18:36, Ambrose Bonnaire-Sergeant 
abonnaireserge...@gmail.com wrote:
 Have you tried naming the anonymous functions that might be culprits?
 
 (fn trace-me [..] ...)

Yes, that turned out to be the quickest way, naming everything with a vim 
command:
  :%s/fn \[/\=fn TRACE- . line(.) .  [/g
Fixing the bug, and then just removing the names again:
  :%s/TRACE-[0-9]* //g

But I'm still interested if there's a pure clojure generated-name to location 
solution I could just call from the REPL.


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.


What does ^{} actually translate to?

2014-05-08 Thread Pascal Germroth
Hi,

I'm trying to attach metadata to some values (not the vars holding them).
I thought ^{x} y was the same as (with-meta y {x}), but while it works for 
f2/f4, f1's metadata is nowhere to be found, while f3 works as expected:

(def f1 doc ^{:x 1} (partial inc))
(meta f1) ; nil, unexpected
(meta #'f1) ; contains :doc, but not :x, as expected

(def f2 doc ^{:x 2} #(inc %))
(meta f2) ; {:x 2}, as expected
(meta #'f2) ; contains :doc, but not :x, as expected

(def f3 doc (with-meta (partial inc) {:x 3}))
(meta f3) ; {:x 3}

(def f4 doc (with-meta #(inc %) {:x 4}))
(meta f4) ; {:x 4}

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.


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.