如何为dolist样式宏创建迭代驱动程序?

时间:2014-07-26 01:09:14

标签: loops common-lisp

假设我有这样的dolist风格宏:

(defmacro do-factorials (var n &body body) 
  (let ((i (gensym)))
    `(let ((,var 1))
       (dotimes (,i ,n)
     (setf ,var (* ,var (1+ ,i)))
     ,@body)))))

我想为iterate库创建一个驱动程序,这可以让我做这样的事情:

(iter (for x in-factorials 10)
      (for y in '(a b c d e))
      (format t "~a ~a~%" x y))

但是,据我所知,iter宏只能扩展为扩展到其他iterate子句的子句,而为此,我需要能够将其他代码包装在do-factorials中。无论如何以可靠的方式做到这一点?

in-hashtable和in-package工作的实现类似于我的因子如何工作,但它们是使用内部函数和宏实现的,我宁愿不使用未导出或记录的符号。

对于这个简单的情况,用iterate重写它很容易,但是,一般来说,这并不总是可行的。例如,do-whatever宏可以来自第三方库。

1 个答案:

答案 0 :(得分:1)

我还没有真正使用过cl:iterate,但根据7.2 Writing Drivers中的文档和示例,我想出了这个:

(defmacro-driver (FOR var IN-FACTORIALS n)
  "All the factorials from 1! to n!."
  (let ((end (gensym))
        (fact (gensym))
        (index (gensym))
        (kwd (if generate 'generate 'for)))
    `(progn
       (with ,end = ,n)
       (with ,fact = 1)
       (with ,index = 0)
       (,kwd ,var next (progn (incf ,index)
                              (if (> ,index ,end) (terminate))
                              (setf ,fact (* ,fact ,index)))))))

在评估完之后,我可以运行您展示的代码:

CL-USER> (iter (for x in-factorials 10)
               (for y in '(a b c d e))
               (format t "~a ~a~%" x y))
1 A
2 B
6 C
24 D
120 E
NIL

根据文档,你仍然可能想要处理&sequence的东西,但是(不是cl:iterate用户),我不确定是否有必要对于不是序列的东西:

  

我们仍然缺少一件事:& sequence关键字。我们可以得到   他们很容易写,

(defmacro-driver (FOR var IN-WHOLE-VECTOR v &sequence)
  …)
     

我们现在可以参考包含其中一个的参数from,to,by等   相应关键字的值,如果关键字为,则为nil   不提供。为这些关键字实现正确的代码是   繁琐而不困难;它留作练习。但之前   你开始吧,请参阅下面的defclause-sequence以获得更简单的方法。

当你说:

时,我不确定这是否属于你的意思
  

对于这个简单的情况,用iterate重写它很容易,但是,   总的来说,这并不总是可行的。例如,做什么   宏可以来自第三方库。

通常,宏do-xxx不一定会暴露其迭代技术,这意味着您无法将其实现应用于迭代。我真的没有看到解决方法,所以我认为你可能不得不用cl:iterate重写一些。但是,我没有使用文档中没有描述的任何内容(我对cl:iterate完全不熟悉),所以我认为你是安全的:

  

in-hashtable和in-package工作的实现类似于如何实现   我的因子可以工作,但它们是使用内部实现的   函数和宏,我宁愿不使用符号   不会导出或记录。