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

Reply via email to