Hi Mark,

Am 17.12.2008 um 23:48 schrieb Mark Volkmann:
Here's an example from Stuart Halloway's book.

(defmacro chain
 ([x form] (list '. x form))
 ([x form & more] (concat (list 'chain (list '. x form)) more)))

(macroexpand '(chain arm getHand getFinger getNail) ; I added the getNail part.

The result is (. (. (. arm getHand) getFinger) getNail)

I'm having trouble understanding how this works.
In the first call, x is arm, form is getHand, and more is '(getFinger
getNail), right?
I expected that more would be processed recursively, but it seems to
me that only form is processed recursively.
Somebody please straighten me out here.

Just step through it step-by-step:

(chain arm getHand getFinger getNail)

First expansion: x = arm, from = getHand, more = (getFinger getNail)

=> (concat (list 'chain (list '. x form)) more)
=> (concat (chain (. arm getHand)) (getFinger getNail))
=> (chain (. arm getHand) getFinger getNail)

Second expansion: x = (. arm getHand), form = getFinger, more = (getNail)

=> the rest is as above.

It works similar to the -> macro from clojure.core. It basically
calls itself on the result of the previous call until all
remaining arguments are consumed.

I don't know the context in which this macro is shown,
and I don't want to step on anyone's toes, but it should
be using syntax-quote:

(defmacro chain
  ([x form] `(. ~x ~form))
  ([x form & more] `(chain (. ~x ~form) ~...@more)))

I think also makes the way it works clearer visible, IMHO.
syntax-quote should be the standard way to write macros
and we should encourage its use as much as possible.

The original macro has a problem, when the user defines
a chain macro on its own. This is captured by the above
expansion. This could be solved by using `chain instead
of 'chain. Still, I think the syntax-quote form is clearer on
what's happening.

Hope this helps.

Sincerely
Meikel

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to