That does look better. I had trouble with the anonymous func, however. After working it out, here's what I think the problem is, as well as what I did about it. ~...@body expands the body (which is a list) so that the elements of the list are represented without the surrounding parens. However, each element already carried it's own parens along with it. So when you do: `(let [body# #(~...@body)] That expands to something like this: `(let [body# #((some-fn) (another-fn))] Which... isn't right. I found two ways to fix this. The first was to wrap the splicing in a do: `(let [body# #(do ~...@body)] Or to create an anonymous function the long way: `(let [body# (fn [] ~...@body)]
Either way, a working form of your improvement would be: (defmacro dowhile [test & body] `(let [body# (fn [] ~...@body)] (body#) (while ~test (body#)))) Thank you, Howard, that is much better than my original version (also, thank you for making me think. I think I actually learned a few things there). On Oct 9, 4:40 pm, Howard Lewis Ship <hls...@gmail.com> wrote: > I'd tend to code this so that the test was the first form, and then > any number of additional remaining forms become the body, in an > implicit do. Obviously, if you're writing something like this, its > for side effects. > > In addition, I'd wrap the body in an annonymous function, defined in a > let, so that the code of the body only needs to exists once in the > macro. > > This is off the top of my head: > > (defmacro dowhile [test & body] > `(let [body# #(~...@body)] > (body#) > (while ~test (body#)))) > > > > On Fri, Oct 9, 2009 at 12:56 PM, nilamo <7nil...@gmail.com> wrote: > > > Hey all. I'm pretty new to Clojure, and wanted to try my hand at > > writing a macro. > > > 'dowhile' is nothing special, but I'd still like to hear any comments/ > > suggestions you may have. > > > (defmacro dowhile [body test] > > `(do ~body (while ~test ~body))) > > > A test shows... > > (macroexpand-1 '(dowhile (dosync (alter x inc)) (< @x 5))) > > => (do (dosync (alter x inc)) (clojure.core/while (< (clojure.core/ > > deref x) 5) (dosync (alter x inc)))) > > > And to show that it works... > > (def x (ref 0)) > > (println @x) ; 0 > > (dowhile (dosync (alter x inc)) (< @x 5)) > > (println @x) ; 5 > > > (dowhile (dosync (alter x dec)) (> @x 7)) > > (println @x) ; 4 > > > Thanks in advance. > > -- > Howard M. Lewis Ship > > Creator of Apache Tapestry > > The source for Tapestry training, mentoring and support. Contact me to > learn how I can get you up and productive in Tapestry fast! > > (971) 678-5210http://howardlewisship.com --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---