2

Paul Graham のANSI Common Lispを読んでいます。マクロに関する章で、彼は次の例を示しています。

(defmacro in (obj &rest choices)
  (let ((insym (gensym)))
   `(let ((,insym ,obj))
      (or ,@(mapcar #'(lambda (c) `(eql ,insym ,c))
                    choices))))) 

(最初の引数が他の引数のいずれかと等しい場合に true を返します)

彼は、それを関数として書くことはできないと考えています。この機能は同じ機能を持っていませんか?

(defun in (obj &rest choices)
  (reduce (lambda (x y)
            (or x (eql y obj)))
          choices
          :initial-value nil))

私が見る違いは、マクロは eql 引数が見つかるまで引数のみを評価するということです。あれですか?

4

2 に答える 2

4

要点は、マクロ バージョンが引数を遅延して評価し (OR に展開され)、一致が見つかった場合に停止することです。funcall は常にすべての引数を最初に評価するため、これは関数では実現できません。

于 2012-05-13T10:31:54.023 に答える
3
> (macroexpand '(in 42
                    (long-computation-1)
                    (long-computation-2)
                    (long-computation-3)))

(LET ((#:G799 42))
  (OR (EQL #:G799 (LONG-COMPUTATION-1))
      (EQL #:G799 (LONG-COMPUTATION-2))
      (EQL #:G799 (LONG-COMPUTATION-3))))

同じ効果を得るには、次のように記述する必要があります。

(defun in (obj &rest choices)
  (reduce (lambda (x y)
             (or x (eql (funcall y) obj)))
          choices
          :initial-value nil))

次のように使用します。

(in 42
    (function long-computation-1)
    (function long-computation-2)
    (function long-computation-3))
于 2012-05-13T11:22:18.020 に答える