Michael Bevilacqua-Linn on 3 Feb 2011 07:52:39 -0800


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: let substitution in clojure?


+1 for looking at clojure.contrib.match (though I assume this is a class project or some such).

Anyhow, in this case, it's not even a matter of one macro calling another.  It's just that binds
doesn't get evaluated at any point. 

So passing anything other than a literal vector in as the bindings won't work:

match.core=> (def my-bindings ['x 1 'y 2])
#'match.core/my-bindings
match.core=> my-bindings
[x 1 y 2]
match.core=> (sub my-bindings (+ x y))
#<CompilerException java.lang.IllegalArgumentException: let requires a vector for its binding (REPL:27)>
match.core=> (macroexpand-1 '(sub my-bindings (+ x y)))
(clojure.core/let my-bindings (+ x y))
 
I don't think the code you've got will help either...  What needs to be evaled, I think, is just the bindings.

Thanks,
MBL

On Thu, Feb 3, 2011 at 10:32 AM, Sean Devlin <francoisdevlin@gmail.com> wrote:
You're running into macro resolution issues.  This is very common when you have a macro calling another macro.  In this situation macroexpand & macroexpand-1 are your friends.  I always use them in debugging & designing macros. 

I think adding an explicit eval will get you the result you want:

(eval `(sub ~(domatch (x y z) (1 2 3)) (+ x y z)))

This is a fundamental constraint of composing macros. 

You should also look at clojure.contrib.match, it's a matching lib for clojure. 




On Thu, Feb 3, 2011 at 6:02 AM, Dan Mead <d.w.mead@gmail.com> wrote:
Hi guys, I'm having trouble figuring out the proper way to do some
macro stuff for my project.

I've got a pattern matcher that works as you'd expect. I can take
patterns which are quoted s-expressions and match them to actual
values. This returns a set of bindings, which I want to use to rewrite
a corresponding _expression_.

it's working with a regular dumb function that crawls down a quoted
_expression_ and does replacement with the bindings list. This is pretty
bad as it runs in theta(n) time, and is really brittle when it comes
to scoping issues.


So, I'm trying to get a macro that will splice the bindings list as a
vector and the target _expression_ into a let statement. That way
scoping should be less of an issue and it should run in constant time
(or whatever let run in etc etc)


so, to match some pattern to a set of values we can do

user=> (match '(x y z) '(1 2 3))
((x 1) (y 2) (z 3))

If that call to the matcher is wrapped in some stuff to convert to a
vector, we can do

user=> (domatch '(x y z) '(1 2 3))
[x 1 y 2 z 3]

and clojure agrees that it's a vector

user=> (vector? (domatch '(x y z) '(1 2 3)))
true

if i have a macro like this

(defmacro sub [binds expr]
 `(let ~binds ~expr))

which works fine, if you give it a literal vector

user=> (sub [x 1 y 1] (+ x y))
2

then why doesn't it work with my call to the matcher?

user=> (sub (domatch '(x y z) '(1 2 3)) (+ x y z))
java.lang.IllegalArgumentException: let requires a vector for its
binding (NO_SOURCE_FILE:0)


I'm afraid I've lost the plot here. Any insight you guys could give
would be helpful

Here is my newbie and entirely too verbose code.

http://taz.cs.wcupa.edu/~dmead/patternmatch.clj

Dan

sorry if you get this post twice