Thanks Meikel, if I may reply to your points and your function as it's slightly different from what I wanted:
> * It's a function, not macro. I need it to be a macro because it's more usable for my purposes that way. The newLISP function is being used to generate templates php-style: <table> <tr><td>Name</td><td>Email</td></tr> <% (for-query-with-db db "SELECT * FROM people" %> <tr><td><%=NAME%></td><td><%=EMAIL%></td></tr> <% ) %> </table> As you can see it's much more convenient as a macro. > * You don't have to fiddle with magic names. The user can choose himself. These aren't magic names, they're just like you keywords, except they're symbols, and they're not magic because they're defined by the columns of the table. Or, I may be misunderstanding your use of the term 'magic'. > * The query can be also stored in some local and doesn't have to be a literal > string. There's nothing forcing you to use it as a literal, the newLISP version can be used with a let statement just as your example did. After discussing this problem with the folks on #clojure they helped me refine my attempt at writing a clojure version of it: (def col-names ["name" "age"]) (def col-vals [["Sally" 5] ["Sue" 6]]) (defmacro foo [& body] (let [col-syms (for [n col-names] (-> n .toUpperCase symbol)) exprs (for [v col-vals] `(let [~@(interleave col-syms v)] ~...@body))] `(do ~...@exprs) ) ) (foo (prn NAME)) As I'm not yet experienced in Clojure enough to use an actual db, I used the vars 'col-names' and 'col-vals' as placeholders. That seems to work great, what I'm fuzzy on is the whole macroexpansion thing and when it occurs. As in this example everything is known at compile-time, is this "macro-expanded" at compile time? Can this sort of macro work just fine when the column information is only known at runtime? Are there any performance considerations? Thanks! - Greg On Feb 4, 2010, at 1:42 AM, Meikel Brandmeyer wrote: > Hi, > > On Feb 4, 4:42 am, Greg <g...@kinostudios.com> wrote: > >> The magic happens here: >> >> (while (list? (setf values (sql:next-row))) >> (eval (expand (cons 'begin $args) (unify keys >> values))) >> ) >> >> $args is equivalent to the 'body' in [& body] in clojure, and the expand >> function will replace all of the symbols in 'keys' (in $args) with the >> 'values'. >> >> So (println NAME) becomes (println "José Lopez"), and it gets eval'd each >> time in the loop to the different values in the table. >> >> How would you implement this behavior in Clojure? > > (defn do-query > [db query thunk] > (doseq [entry (-> db (.prepareStatement query) .executeQuery > resultset-seq)] > (thunk entry))) > > (let [q "SELECT name FROM people"] > (do-query db q #(println (:name %)))) > > Several differences to the newLisp code: > > * It's a function, not macro. > * You don't have to fiddle with magic names. The user can choose > himself. > * The query can be also stored in some local and doesn't have to be a > literal > string. > > I am really happy that I'm a smug Clojure weenie, who doesn't have to > write > code which walks other code to replace things in place and to eval > it... > > Sincerely > Meikel > > -- > 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 -- 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