On 21 April 2010 22:58, Kevin Livingston
<kevinlivingston.pub...@gmail.com> wrote:
> Thank you for taking the time to provide feedback.

Thank you for the insightful response!

I've posted the current state of my code -- which uses clojure.zip and
clojure.walk, among other things -- here:

http://gist.github.com/374764

> intentionally driving into an exception seems like a very bad idea.
> but yes I can define my own equivalent of consp I was just hoping
> there was something I was over looking.

Right. I've aliased clojure.contrib.core/seqable? to compound? for
now... which I hadn't known about earlier. I guess this was bound to
be a solved problem. Agreed on the use of exceptions.

> That'll trade some heap for stack space, presumably worthwhile.  I
> haven't had to do much hand optimization of recursion so I'm a little
> rusty (the Franz Allegro compiler was fairly amazing in that
> regard)... I was hoping there was some even better trick (like the
> trampoline) to save me even more.

I did write a version of occurs-check -- which I seem to have renamed
to occurs? at some point -- which uses the CPS approach (it's included
in the Gist, commented out); then I realised that its a natural use
case for clojure.zip (the same basic idea, but with a different
packaging). See if you like the current version.

> that "extra" paren is there too because the body of the clause is an
> implicit progn in common lisp.

And an implicit begin in Scheme, I know... Plus the Scheme version
handles unary clauses and a special kind of ternary clauses (with '=>
in the middle) in special ways, which is useful at times. However, the
reason I personally prefer to have those extra parens in cond has much
more to do with the shape of the code than those other things. :-)

> on some issues I agree others I disagree, regarding your code:

Thanks again for your remarks. A few points that came to my mind:

> regarding removing the helper functions, that's not necessarily ideal,
> while bindings may always be a map putting in literals like {} or nil
> instead of fail or no-bindings actually obfuscates the code, and makes
> it harder to change later if what bindings is needs to fundamentally
> change.

I'm in two minds w.r.t. the second point above. On the one hand, I'm
loathe to pass on using such facilities as the IFn implementation on
maps, sets and vectors in an attempt to make easier some fundamental
change which might possibly happen in the future (and who knows what
else it might involve besides what I might think of now). On the
other, I can already see a different data structure being useful for
representing bindings (more on that further down), so I'm also
disinclined to hand-wave your argument away.

However, I do believe that said different data structure could be made
to act like a map fairly transparently (hopefully through the protocol
facility; or, if some functionality's missing as of yet, reify), so
I'd still prefer to use the map-specific niceties and refactor to
remove them only when the need actual comes (and it becomes clear what
sort of changes are really needed).

> in general it's bad style to wrap a cond with another test if
> trivially avoidable (at least this is coming from best practice common
> lisp style) so for example, in your code line 24, there's no reason to
> pull that out of the cond, especially since you are also using the
> return value of the when, it's better to be explicit about the test
> and what it's resulting return value is -- in this case that the
> unification fails.

Well, I was trying to treat failure specially, as it were, but I take
your point. Changed now.

> the if-let's are a little more interesting as it
> potentially saves one lookup, but it seems to make  the code far more
> "disjoint" or at least increase the number of paths.

I've included my cond-let macro in the Gist now (and refactored
unify-variable to take advantage of it); do you think it's acceptable?

> the changing of a cond to a some with the identity function on line 48
> seems like a very odd choice to me.  while still correct code I see no
> reason why this would be preferred to a cond.

Ouch, I don't know what I was thinking. Changed now.

> I'm torn about the simplify-bindings -- I think it's a cool function
> to have, because if what you are subbing into is large compared to
> bindings, this is probably a win, but if you have a lot of bindings
> and are only using some, you could spend a lot of time to pack them
> down.  it'd probably be good to have around if someone knew where they
> were in the trade-off.

Perhaps using some kind of local memoization would be a good
compromise? There was a cool thread on memoization here a short while
ago; see Meikel Brandmeyer's summary here:

http://kotka.de/blog/2010/03/memoize_done_right.html

I took a shot at that with subst-memo. Additionally, this function
leaves unbound variables intact, while the other versions use nil
instead. There are two other (simpler) versions of subst included in
the current gist, of which one is equivalent to my initial version,
while the other one resolves variables when the need arises (and
doesn't memoize). I've switched to prewalk for all three versions,
like you did.

As an alternative to a fancy substitution scheme, I was thinking of a
different data structure for bindings, as mentioned above... Something
like a reversible map. With reify, it should be able to make such a
beast behave as a regular IPersistentMap, but also support
lookup-of-key-by-val through a protocol, say, and use that inside
assoc to perform resolution at binding time. Not sure if that would
really be beneficial, and even if it would, I guess that it might not
be worth the trouble when memoization should handle things nicely
enough. The idea did make me less certain that all one could ever hope
to use as a bindings structure is a hash map, though. ;-)

All the best,
Michał

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