Recursion vs. iteration in Lisp macro I've been programming Clojure for a little while and recently started learning Common Lisp. One of my favorite things about Clojure is the threading operator -&gt;, which greatly simplifies long chains of nested function calls. Naturally I wanted to have this in Common Lisp.

I found an implementation here:


(defmacro -&gt; (x &amp;rest args)
  (destructuring-bind (form &amp;rest more)
      args
    (cond
      (more `(-&gt; (-&gt; ,x ,form) ,@more))
      ((and (consp form)
            (or (eq (car form) 'lambda)
                (eq (car form) 'function)))
       `(funcall ,form ,x))
      ((consp form) `(,(car form) ,x ,@(cdr form)))
      (form `(,form ,x))
      (t x))))



This uses a recursive macro expansion; I've read that it's better to use iteration over recursion in CL when you can, so I wrote my own version:

(defmacro -&gt; (x &amp;rest forms)
  (labels ((expand-form (x form)
             (if (consp form)
                 (if (or (eq (car form) 'lambda)
                         (eq (car form) 'function))
                     `(funcall ,form ,x)
                     `(,(car form) ,x ,@(cdr form)))
                 `(,form ,x))))
    (do ((forms forms (cdr forms))
         (x x (expand-form x (car forms))))
        ((not forms) x))))


I'm relatively new to Lisp so I don't know how to judge which way is better. Any comments, suggestions?

EDIT: I knew something was fishy! You don't have to use any looping constructs at all, a plain old reduce will cut it:

(defmacro -&gt; (x &amp;rest forms)
  (flet ((expand-form (x form)
           (cond
             ((atom form)
              `(,form ,x))
             ((member (car form) '(lambda function))
              `(funcall ,form ,x))
             (t
              `(,(car form) ,x ,@(cdr form))))))
    (reduce #'expand-form forms :initial-value x)))
I think the first version is slightly more elegant and looks okay to me.

In the second version, I would replace LABELS with FLET. LABELS would indicate some kind of recursion.

Generally I would also think if the nested expansion is something I would want, vs. an expansion into a LET* form.

I would also replace CAR and CDR with FIRST and REST.

The DESTRUCTURING-BIND is also not necessary:

(defmacro -&gt; (x form &amp;rest more)
  (cond (more
         `(-&gt; (-&gt; ,x ,form) ,@more))
        ((and (consp form)
              (member (first form) '(lambda function)))
         `(funcall ,form ,x))
        ((consp form)
         `(,(first form) ,x ,@(rest form)))
        (form
         `(,form ,x))
        (t x)))