1

マクロに渡されたパラメーターがどのように評価されるのか疑問があります。詳細は以下をご覧ください。

このマクロが定義されています

(defmacro test-macro (xlist)
    `(* ,@xlist))

このグローバル変数があります(defvar *test-list* '(1 100 2 200))

*test-list*このマクロに渡されると(test-macro *test-list*)、このエラーが返されます -

value *TEST-LIST* is not of the expected type LIST.
   [Condition of type TYPE-ERROR]

しかし、関数をこれに変更すると、リストが返されます

(defmacro test-macro (xlist)
    `(,@xlist)) ;; removed the * operator

(test-macro *test-list*)戻り(1 100 2 200)ます。

,@xlistしたがって、最初のケース、つまり*演算子が適用されたときに が評価されない理由は疑問です。どんな助けでも大歓迎です。

4

2 に答える 2

4

マクロをデバッグするときの正しい方法はmacroexpand、マクロ形式を評価するのではなく、 を使用することです。たとえば、あなたの場合:

(defmacro test-macro1 (xlist) `(* ,@xlist))
(macroexpand '(test-macro1 foo))
==> (* . FOO)
(defmacro test-macro2 (xlist) `(,@xlist))
(macroexpand '(test-macro2 foo))
==> FOO

どちらもおそらくあなたが望むものではありません。

于 2013-02-27T04:01:29.830 に答える
3

混乱は、マクロがプリプロセッサであるということです。実行時の値を知るための組み込みのメカニズムがありません。したがって、この用語を使用する場合:

(test-macro test-list)

マクロが認識するのは識別子test-listだけです。実行時の値がリストであることを事前に認識しておらず、ソースプログラムがこの変数識別子を使用していることだけを認識しています。

マクロはソースからソースへのリライターです。プログラムのダイナミクスについては知りません。より賢いコンパイラーは、テストリストが定数であることを認識してインライン化を行うことができるかもしれませんが、マクロエキスパンダーはそれほど賢くはありません。

あなたができることはおそらく次のようなものです:

(defmacro test-macro (xlist)
  (cond
    (;; If we see test-macro is being used with a quoted list of things
     ;; then we can rewrite that statically.
     (and (pair? xlist)
          (eq? (car xlist) 'quote)
          (list? (cadr xlist)))
     `(list 'case-1 (* ,@(cadr xlist))))

    (;; Also, if we see test-macro is being used with "(list ...)"
     ;; then we can rewrite that statically.
     (and (pair? xlist)
          (eq? (car xlist) 'list))
     `(list 'case-2 (* ,@(cdr xlist))))

    (else
     ;; Otherwise, do the most generic thing:
     `(list 'case-3 (apply * ,xlist)))))



;; This hits the first case:
(test-macro '(3 4 5))

;; ... the second case:
(test-macro (list 5 6 7))

;; ... and the third case:
(defvar test-list '(1 100 2 200))
(test-macro test-list)

2番目のバージョンに関して:マクロ:

(defmacro test-macro (xlist)
  `(,@xlist))

と同等です:

(defmacro test-macro (xlist)
  xlist)

そのため、最初のバージョンで受け取ったエラーは発生しません。

于 2013-02-27T04:08:36.113 に答える