I usually try to teach myself lisp, and as an exercise in macro writing, I try to create a macro to define a closed loop of arbitrary depth. I work with sbcl using emacs and slime.
To get started, I wrote this macro with two loops:
(defmacro nested-do-2 (ii jj start end &body body) `(do ((,ii ,start (1+ ,ii))) ((> ,ii ,end)) (do ((,jj ,ii (1+ ,jj))) ((> ,jj ,end)) ,@body)))
which I could use as follows:
(nested-do-2 ii jj 10 20 (print (+ ii jj)))
By the way, I originally wrote this macro using gensym to generate loop counts (ii, jj), but then I realized that the macro was pretty useless if I could not access the counters in the body.
In any case, I would like to generalize the macro to create a nested loop loop that will be nested at an arbitrary level. This is what I have so far, but this does not quite work:
(defmacro nested-do ((&rest indices) start end &body body) `(dolist ((index ,indices)) (do ((index ,start (1+ index))) ((> index ,end)) (if (eql index (elt ,indices (elt (reverse ,indices) 0))) ,@body))))
which I would like to call as follows:
(nested-do (ii jj kk) 10 15 (print (+ ii jj kk)))
However, the list does not expand properly, and I ended up in the debugger with this error:
error while parsing arguments to DEFMACRO DOLIST: invalid number of elements in ((INDEX (II JJ KK)))
And in case this is not obvious, the point of the built-in if statement should execute the body only in the innermost loop. For me, this does not look very elegant, and it has not been tested (since I could not expand the list of parameters yet), but actually this is not a question of this question.
How can I expand a list correctly in a macro? Is the problem a macro syntax or a list expression in a function call? Any other comments would also be appreciated.
Thanks in advance.