[racket] Problem with macro

From: Neil Van Dyke (neil at neilvandyke.org)
Date: Fri Aug 12 10:22:18 EDT 2011

1. Without trying it, I'm pretty sure this particular syntax 
transformation can be done in "syntax-rules", but I'm not certain it can 
be done using only the power of "..." in "syntax-rules", without a 
helper macro.  Your life might be easier if you do this particular 
transformation in "syntax-case" rather than "syntax-rules".

2. If you use "syntax-rules" instead of "syntax-case", three tips: (1) 
break it up into mutiple macros, so you can have secret recursive helper 
macros that have arguments for lists of input that you haven't processed 
and arguments for lists of output from that processing, such as for 
assembling lists of "letrec" or "case" clauses; (2) instead of 
"process-state", you can have your helper macros assemble some of the 
ultimate code *bottom-up*, so that, for example, things like the 
"letrec" clauses (or "case" clauses, or parts of "case" clauses) get 
assembled first, and only after all the clauses are assembled do the 
"letrec" and other unchanging stuff around them get assembled; and (3) 
it's good to expand to "case"/"if"/"and"/"or" for control flow, but 
avoid expanding to "cond", because it's syntactic-sugary, and you'd have 
to worry about "else" and "=>" appearing in your macro input.

3. You've picked a somewhat tricky macro for "syntax-rules" -- harder 
than most "syntax-rules" macros you'll usually want to implement.  But 
once you can implement this macro, I think you'll then have the tools to 
implement most any other "syntax-rules" macro you want to in the 
future.  If you get stuck on this one, try simpler ones that isolate a 
single tricky part.  For example, contrive a programming exercise of a 
macro that's a thin veneer around "case", and implement your macro using 
a recursive helper macro rather than "...", to assemble each "case" 
clause, one clause per recursion step.  (Or just use "syntax-case", and 
be done with it.)

4. Before you spend too much time writing a macro for that particular 
transformation, you might want to experiment some more with that example 
you gave of code you're trying to transform to.  See whether your state 
transitions can simply can use tail calls to your "letrec" bindings for 
the state closures, so that you need neither the "curr-state" variable 
not the "ok" and "endstate" values.  That would be more 
Racket-idiomatic, the compiler might be able to optimize the code 
better, and it might make your macro easier to implement.

(Pardon the writing in enumerations, but someone erroneously put caf 
coffee in the decaf coffee carafe.)


Posted on the users mailing list.