1

以下に、整数のビットに沿って反復するマクロがあります。次のように、ループの収集機能を統合したいと思います。

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

1 に答える 1

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)
于 2012-09-04T15:49:30.037 に答える