您不需要引号,因为无论如何都需要在编译时知道尺寸和变量。
(defmacro nested-loops (dimensions variables &body body)
(loop for range in (reverse dimensions)
for index in (reverse variables)
for x = body then (list y)
for y = `(loop for ,index from 0 to ,range do ,@x)
finally (return y)))
编辑:
如果在编译时无法确定尺寸,我们需要一个函数
(defun nested-map (fn dimensions)
(labels ((gn (args dimensions)
(if dimensions
(loop for i from 0 to (car dimensions) do
(gn (cons i args) (cdr dimensions)))
(apply fn (reverse args)))))
(gn nil dimensions)))
并在调用时将主体包裹在 lambda 中。
CL-USER> (nested-map (lambda (&rest indexes) (print indexes)) '(2 3 4))
(0 0 0)
(0 0 1)
(0 0 2)
(0 0 3)
(0 0 4)
(0 1 0)
(0 1 1)
(0 1 2)
(0 1 3)
(0 1 4)
(0 2 0)
(0 2 1)
...
编辑(2012-04-16):
上面版本的nested-map 是为了更接近地反映原始问题陈述而编写的。正如 mmj 在评论中所说,将索引范围从 0 到 n-1 可能更自然,如果我们不坚持迭代的行优先顺序,将反转移出内部循环应该会提高效率。此外,让输入函数接受一个元组而不是单个索引可能更明智,以使其与排名无关。这是一个带有所述更改的新版本:
(defun nested-map (fn dimensions)
(labels ((gn (args dimensions)
(if dimensions
(loop for i below (car dimensions) do
(gn (cons i args) (cdr dimensions)))
(funcall fn args))))
(gn nil (reverse dimensions))))
然后,
CL-USER> (nested-map #'print '(2 3 4))