Suggestions for macro
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. --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
Re: Suggestions for macro
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-5210 http://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 -~--~~~~--~~--~--~---
Re: Suggestions for macro
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 -~--~~~~--~~--~--~---