2012-09-04 32 views
1

我有一个宏,它沿着整数中的位进行迭代。我想集成这样的循环的收集能力:如何在common lisp中修改这个宏来集成循环中的collect?

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

回答

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) 
+0

所以我应该如何整合这跟我所提供的宏? – Mark

+0

我认为像这样的宏组合会工作:(with-collector()(do-bits ....)) –

+0

更新了答案以显示如何。 – Lex