如何为列表风格的宏制作迭代驱动程序?



假设我有这样一个列表样式的宏:

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

我想为迭代库做一个驱动程序,它将允许我做这样的事情:

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

然而,据我所知,iter宏只能使用扩展为其他迭代子句的子句进行扩展,而为此,我需要能够将其他代码包装在do-阶乘中。有什么方法可以可靠地做到这一点吗?

in-hashtable和in-package的实现类似于我的in-factorial的工作方式,但它们是使用内部函数和宏实现的,我不希望使用没有导出或记录的符号。

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

我还没有真正使用cl:iterate,但基于7.2编写驱动程序中的文档和示例,我想到了这个:

(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用户),我不确定是否有必要或不为一些不是一个序列:

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

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

现在可以引用形参from、to、by等,这些形参都包含这两个参数对应关键字的值,如果关键字为不提供。为这些关键字实现正确的代码是繁琐但不困难;这是一个练习。但在您可以从下面的defclause-sequence中找到更简单的方法。

我不确定这是否符合你所说的:

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

一般来说,宏do-xxx不一定公开它的迭代技术,这意味着您不能将其实现coöpt变为迭代。我真的找不到解决这个问题的方法,所以我认为你可能需要用cl:iterate来重写一些。但是,我没有使用文档中没有描述的任何内容(并且我对cl:iterate完全陌生),因此我认为您使用:

是安全的。

in-hashtable和in-package的实现方式类似我的阶乘也可以,但是它们是用internal实现的函数和宏,我不喜欢使用符号

最新更新