Whoops, I need to correct this statement:

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

Indeed in the original newlisp version I gave you wouldn't be able to use it 
with the let form, but that's because I wrote it incorrectly, I left out the 
eval on the 'query', it should be this:

        (letn (db (eval db) sql (db:prepare-sql (eval query)) keys '())

One other note I should make so as to avoid confusion: using 'eval' is frowned 
upon in clojure because it's ridiculously slow, however it's OK to use it in 
newLISP because newlisp's eval is very fast, there's little to no penalty for 
using it, which is why you'll find it frequently used in newlisp code.

Please don't take that to mean that I think one language is better than the 
other, I think both are great and it's why I'm asking these questions. :-)

- Greg

On Feb 4, 2010, at 12:55 PM, Greg wrote:

> 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

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