I mentioned earlier that the macro-generating macro was essentially done. There is one more new control loop that I find frequent need of. Sometimes, it is sufficient to loop over the values, I don’t actually need a user-visible variable with the iterator itself. So, we can build a new looping construct that loops through the contents of the dl-list, instead of through iterators into the dl-list. This time, we’ll jump right to the general case.
(defmacro create-n-value-loop (n name iter-loop-to-use) (assert (and (integerp n) (> n 0))) (let (value-symbols iter-symbols) (dotimes (i n) (push (intern (format nil "ITER~D" i)) iter-symbols) (push (intern (format nil "VALUE~D" i)) value-symbols)) (setf iter-symbols (reverse iter-symbols)) (setf value-symbols (reverse value-symbols)) `(defmacro ,name ((dl-list ,@value-symbols &key start end circular reverse) &body body) (let ((dl-cap (gensym)) ,@(mapcar #'(lambda (x) `(,x (gensym))) iter-symbols)) `(let ((,dl-cap ,dl-list)) (,',iter-loop-to-use (,dl-cap ,,@iter-symbols :start ,,'start :end ,,'end :circular ,,'circular :reverse ,,'reverse) (let (,,@(mapcar #'(lambda (x y) ``(,,x (iter-contents ,,'dl-cap ,,y))) value-symbols iter-symbols)) ,@body)))))))
This creates macros like value-loop, the by-hand version of which is reproduced here:
(defmacro value-loop ((dl-list value0 &key start end circular reverse) &body body) (let ((dl-cap (gensym)) (iter (gensym))) `(let ((,dl-cap ,dl-list)) (iter-loop (,dl-cap ,iter :start ,start :end ,end :circular ,circular :reverse ,reverse) (let ((,value0 (dl-list:iter-contents ,dl-cap ,iter))) ,@body)))))