我有一个宏,它沿着整数中的位进行迭代。我想整合循环的收集功能,如下所示:
(loop for x in '(a b c d e)
for y in '(1 2 3 4 5)
collect (list x y) )
我应该如何修改下面的宏来完成上述工作?
(defmacro do-bits ((var x) &rest body)
"Evaluates [body] forms after binding [var] to each set bit in [x]"
(let ((k (gensym)))
`(do ((,k ,x (logand ,k (1- ,k))))
((= ,k 0))
(let ((,var (logand ,k (- ,k))))
,@body))))
答案 0 :(得分:2)
这是一个简单的宏with-collector
应该可以解决这个问题:
(defmacro with-collector ((&optional (collector-name 'collect)) &body body)
(let ((result (gensym)))
`(let ((,result (list)))
(flet ((,collector-name (arg) (push arg ,result)))
(progn ,@body)
(when ,result
(nreverse ,result)))))
默认使用名称collect
:
(with-collector ()
(collect 'a)
(collect 'b)); => (A B)
但如果您愿意,可以使用其他名称(例如,用于嵌套或解决符号冲突)
(with-collector (foo)
(foo 'bar)
(foo 'baz)); => (BAR BAZ)
将它与您的宏集成,只需打包do
表单:
(defmacro do-bits ((var x) &rest body)
"Evaluates [body] forms after binding [var] to each set bit in [x]"
(let ((k (gensym)))
`(with-collector ()
(do ((,k ,x (logand ,k (1- ,k))))
((= ,k 0))
(let ((,var (logand ,k (- ,k))))
,@body)))))
和collect
将在正文中提供:
(do-bits (x 255) (collect x))
; => (1 2 4 8 16 32 64 128)
(do-bits (x 256) (collect x))
; => (256)