recursion - 用于嵌套循环的 Lisp 宏(或函数)

标签 recursion macros lisp nested-loops

是否可以编写一个 Common Lisp 宏,它采用维度和变量列表、(迭代的)主体,并创建由列表指定的嵌套循环组成的代码?

也就是说,类似于:

(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 的递归解决方案,非常棒。

最佳答案

您不需要引号,因为维度和变量无论如何都需要在编译时知道。

(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 是为了更准确地反射(reflect)原始问题陈述而编写的。正如 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))

关于recursion - 用于嵌套循环的 Lisp 宏(或函数),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10163298/

相关文章:

vba - Excel VBA 使用变量写入 FDF 文件

android - 如何在android中创建MACROS

programming-languages - 有人知道如何获得 Linux 的 SAM76 源代码吗?

recursion - LISP:如何在递归函数上不使用(Print)或(Format t)函数的情况下输出到控制台

java - 从文本文件中线性搜索字符串数组中的单词

linux - Perl 正则表达式递归替换多个文件组中的字符串,如 "*.php" "*.html"

Scala 宏 Liftable 带有前向引用

java - 使用递归方法进行三元搜索

c++ - 使用 RapidXML/C++ 类指针副作用进行解析时的递归问题

lisp - call-with-current-continuation 只能用 lambda 和闭包来实现吗?