Thank you so much. I'm confused, however, about what functions you're allowed to call inside a macro outside of a quote. I read once that "runtime information" was unavailable during the macro phase. But it seems that one is still allowed to call array-map, apply, take-nth, and vec during the macro phase. What is the pattern for what is allowed or prohibited in macros?
On Feb 13, 10:52 pm, Chouser <chou...@gmail.com> wrote: > On Fri, Feb 13, 2009 at 11:17 PM, samppi <rbysam...@gmail.com> wrote: > > > I'm trying to write a macro that expands from this: > > > (product-context [n rule0, m rule1)] > > (rule-maker2 (+ n m)) rule3)) > > > Into this (assume that conc-fn and conc-products are functions): > > > (fn [tokens] > > (if-let [[remainder# n m] (conc-products [rule0 rule1] tokens)] > > (conc-fn [(rule-maker2 (+ n m)) rule3] remainder#))) > > ...but I can't figure out how to change [n rule0 m rule1] to (if-let > > [[remainder# n m] (conc-products [rule0 rule1] tokens)] ...). > > Try working it out outside of the macro context. > > (def bindvec '[n rule0, m rule1]) > > Now you've got something to work with. There are plenty of acceptible > answers. Maybe you want to think of the vector as key/value pairs: > > (apply array-map bindvec) ==> {n rule0, m rule1} > (keys (apply array-map bindvec)) ==> (n m) > (vals (apply array-map bindvec)) ==> (rule0 rule1) > > Or just use some seq function: > > (take-nth 2 bindvec) ==> (n m) > (take-nth 2 (rest bindvec)) ==> (rule0 rule1) > > Once you've got the pieces you need, try sticking them into a > syntax-quote: > > user=> `(if-let [[r# ~(take-nth 2 bindvec)] (cp ~(take-nth 2 (rest > bindvec)))] ...) > (clojure.core/if-let [[r__215__auto__ (n m)] (user/cp (rule0 rule1))] ...) > > Well, that's close by there are extra parens around (n m) and you want > a vector not a list for the rules. So play with it until it looks > right: > > user=> `(if-let [[r# ~@(take-nth 2 bindvec)] (cp ~(vec (take-nth 2 > (rest bindvec))))] ...) > (clojure.core/if-let [[r__219__auto__ n m] (user/cp [rule0 rule1])] ...) > > Then you're ready to build the macro: > > (defmacro product-context [bindvec & body] > `(fn [tokens#] > (if-let [[remainder# ~@(take-nth 2 bindvec)] > (conc-products [~@(take-nth 2 (rest bindvec))] tokens#)] > (conc-fn [...@body] remainder#)))) > > --Chouser --~--~---------~--~----~------------~-------~--~----~ 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 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 -~----------~----~----~----~------~----~------~--~---