Thank you for taking the time to provide feedback.

> I can't think of a direct equivalent now, but it's straightforward
> enough to supply your own equivalent, like my compound? function
> (basically #(and (seq? %) (seq %))). This won't work on arrays and
> other things which seq can operate upon, but which respond with a
> false to seq?, though. If that could be a problem, you can just use
> seq and for non-seqables catch the exception and return false.

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.


> You could perform a CPS transform by hand (which I haven't (yet) done
> with the code in the Gist). For occurs-check this would mean having an
> extra to-do argument (or maybe just [... & to-do]); whenever false
> would normally be returned, you'd first check if to-do is empty,
> returning false if so and doing (recur <args taken from (first to-do)>
> (rest to-do)) otherwise. true should short-circuit and disregard
> to-do, of course. Finally, whenever occurs-check would normally branch
> on first / rest, it would recur with first *and* an extended to-do
> including rest.

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.  That's a good idea though, I'll
just to estimate how close I'm getting to blowing the stack, and the
overhead of tracking to-do.

> Not at all. next is basically #(seq (rest %)); you might want to use
> it when the extra bit of strictness is beneficial to your code and you
> shouldn't use it when it isn't.

oh, ok.  I saw some posts on using the new super-lazy lists / code and
it implied that next was necessary over rest, but I didn't quite read
it in excruciating detail.

> Good question. I really prefer the fully parenthesised cond clauses
> from Scheme / CL / elisp, in good part because of the nicer
> indentation without particularly elaborate rules... :-(

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


> I think that your code would benefit from direct use of Clojure data
> structure literals and such facilities as the IFn implementation
> available on maps; see my gist for examples of what I have in mind.

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

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.  similarly with truncating variable names, it detracts from
readability - although with one interesting caveat -- "var" is a
particularly unique as it is now a language keyword in clojure.

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

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.


thanks for the subst code.

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.

 I left out Norvig's code, I have a need for binding/substituting with
multiple binding lists so I ended up with this (which requires
clojure.walk)

(defn recursive-replace
  ([expr l-bindings] (recursive-replace expr l-bindings #{expr}))
  ([expr l-bindings past-vals]
     (let [applicable-bindings
           (some (fn [b] (if (contains? b expr) b nil)) l-bindings)
           bind-val (get applicable-bindings expr)]
       (if (or (not applicable-bindings)
               (contains? past-vals bind-val)) ;don't enter replace
loop
         expr
         (recur bind-val l-bindings (conj past-vals bind-val))))))

(defn subst-bindings-int [x l-bindings]
  (prewalk (fn [expr] (recursive-replace expr l-bindings)) x))

(defn subst-bindings-list [x list-of-bindings]
  (cond (some (partial = fail) list-of-bindings) fail
        (every? (partial = no-bindings) list-of-bindings) x
        :else (subst-bindings-int x list-of-bindings)))

(defn subst-bindings [x & bindings]
  "Substitute the value of variables in bindings into x,
  taking recursively bound variables into account."
  (subst-bindings-list x bindings))



thanks again for the new ideas.

Kevin

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