Lisp宏(或函数),用于嵌套循环 [英] Lisp macro (or function) for nested loops

查看:155
本文介绍了Lisp宏(或函数),用于嵌套循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is it possible to write a Common Lisp macro that takes a list of dimensions and variables, a body (of iteration), and creates the code consisting of as many nested loops as specified by the list?

就是这样,

(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)))

关注

正如huaiyuan正确指出的那样,我必须知道在编译时传递给宏的参数.如果您确实需要像我一样的功能,请看下面.

As huaiyuan correctly pointed out, I have to know the parameters to pass to macro at compile time. If you actually need a function as I do, look below.

如果您对宏没问题,请尝试使用6502的递归解决方案.

If you are ok with a macro, go for the recursive solution of 6502, is wonderful.

推荐答案

您不需要引号,因为无论如何在编译时都需要知道尺寸和变量.

You don't need the quotes, since the dimensions and variables need to be known at compile time anyway.

(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)))

如果在编译时无法确定尺寸,则需要一个函数

If the dimensions cannot be decided at compile time, we'll need a function

(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中.

and to wrap the body in lambda when calling.

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可能更自然,如果我们不坚持以行为主的迭代顺序,则将反转移出内部循环应该会提高效率.同样,让输入函数接受元组而不是单个索引(与排名无关)可能更明智.这是具有所述更改的新版本:

Edit(2012-04-16):

The above version of nested-map was written to more closely reflect the original problem statement. As mmj said in the comments, it's probably more natural to make index range from 0 to n-1, and moving the reversing out of the inner loop should improve efficiency if we don't insist on row-major order of iterations. Also, it's probably more sensible to have the input function accept a tuple instead of individual indices, to be rank independent. Here is a new version with the stated changes:

(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))

这篇关于Lisp宏(或函数),用于嵌套循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆