假设我有这样一个列表样式的宏:
(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实现的函数和宏,我不喜欢使用符号