是否有可能编写一个Common宏,该宏接受维度和变量的列表(迭代的主体),并创建由列表指定的尽可能多的嵌套循环组成的代码?
也就是说,就像:
(nested-loops '(2 5 3) '(i j k) whatever_loop_body)应该扩大到
(loop for i from 0 below 2 do
(loop for j from 0 below 5 do
(loop for k from 0 below 3 do
whatever_loop_body)))跟踪
正如怀远正确指出的,在编译时,我必须知道要传递给宏的参数。如果你真的像我一样需要一个函数,请看下面。
如果您可以使用宏,那么使用6502的递归解决方案是很棒的。
发布于 2012-04-15 16:09:42
您不需要引号,因为无论如何都需要在编译时知道维度和变量。
(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)))打电话的时候把身体裹在羊肉里。
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))发布于 2012-04-15 19:37:42
有时,一种有用的方法是编写递归宏,即生成包含同一宏的另一调用的代码的宏,除非情况足够简单,可以直接解决:
(defmacro nested-loops (max-values vars &rest body)
(if vars
`(loop for ,(first vars) from 0 to ,(first max-values) do
(nested-loops ,(rest max-values) ,(rest vars) ,@body))
`(progn ,@body)))
(nested-loops (2 3 4) (i j k)
(print (list i j k)))在上面的变量列表中,如果变量列表为空,则宏直接扩展到主体窗体,否则生成的代码将是第一个变量上的(loop...),其中包含do部分中的另一个(nested-loops ...)调用。
宏不是用于函数的正常意义上的递归(它不是直接调用自己),但是宏扩展逻辑将为内部部分调用相同的宏,直到代码生成完成为止。
注意,内部循环中使用的最大值形式将在外部循环的每次迭代中重新评估。如果表单确实是测试用例中的数字,则没有任何区别,但如果它们是函数调用,则会有所不同。
发布于 2012-04-15 16:08:52
嗯。以下是常见的lisp宏的一个例子。不过,请注意,我不确定,这实际上是一个好主意。但我们在这里都是成年人,不是吗?
(defmacro nested-loop (control &body body)
(let ((variables ())
(lower-bounds ())
(upper-bounds ()))
(loop
:for ctl :in (reverse control)
:do (destructuring-bind (variable bound1 &optional (bound2 nil got-bound2)) ctl
(push variable variables)
(push (if got-bound2 bound1 0) lower-bounds)
(push (if got-bound2 bound2 bound1) upper-bounds)))
(labels ((recurr (vars lowers uppers)
(if (null vars)
`(progn ,@body)
`(loop
:for ,(car vars) :upfrom ,(car lowers) :to ,(car uppers)
:do ,(recurr (cdr vars) (cdr lowers) (cdr uppers))))))
(recurr variables lower-bounds upper-bounds))))其语法与您的建议略有不同。
(nested-loop ((i 0 10) (j 15) (k 15 20))
(format t "~D ~D ~D~%" i j k))扩展成
(loop :for i :upfrom 0 :to 10
:do (loop :for j :upfrom 0 :to 15
:do (loop :for k :upfrom 15 :to 20
:do (progn (format t "~d ~d ~d~%" i j k)))))宏的第一个参数是表单的列表。
(variable upper-bound)(下界为0)或
(variable lower-bound upper-bounds)有了更多的爱,你甚至可以拥有这样的东西
(nested-loop ((i :upfrom 10 :below 20) (j :downfrom 100 :to 1)) ...)但是,如果loop已经具备了所有这些特性,那为什么还要麻烦呢?
https://stackoverflow.com/questions/10163298
复制相似问题