您不需要使用引号,因为在编译时必须知道尺寸和变量。
(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):
上面的嵌套映射版本是为了更接近原始问题陈述而编写的。正如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))