3

仮定しましょう:

(defmacro testing (&optional var)
    `(list 'this 'is  
       ,@(when (consp var) `('a 'list))))

呼び出されたとき:

>(testing 2)
(THIS IS)

>(testing (list 1 2))
(THIS IS A LIST)

それが私が欲しかったものです。しかし今、リストであるパラメーターを渡すと:

>(defparameter bla (list 1 2 3))
BLA
>(testing bla)
(THIS IS)

これは、マクロが(consp bla)bla がリストではなくシンボルである場所をチェックするためだと思いますか? これを防ぐにはどうすればよいですか?

ありがとう

4

2 に答える 2

5

次のようなことができます:

(defmacro testing (&optional var)
   `(if (consp ,var)
        '(this is a list)
        '(this is)))

そのvarため、実行時に評価されます (コンパイル時ではありません)。varマクロの展開では 1 回しか表示されませんが、2 回以上表示される場合は、gensym を使用する必要があります。

'(this is)編集: 2 回入力したくない場合は、次のようにします。

(defmacro testing (&optional var)
  `(append '(this is) (when (consp ,var) '(a list))))

使用しないでくださいeval。遅く、完全に不要です。マクロ展開に代入varすることで、当然実行時に評価されるようになります。eval を使用すると、次のようになります。

(eval (append '(list 'this 'is) (when (consp 'bla) '('a 'list))))

それが実行されるたびに、コードを表すリストが作成され、実行前にコンパイルされます。(これがループに入っていないことを願っています!) 単純なコードを生成するマクロ ( を使用しないeval) を使用すると、コンパイルは 1 回だけになります。

于 2012-02-09T18:24:22.097 に答える
0

ここで問題になるのは、式

,@(when (consp var) `('a 'list))))

引数のリテラル (未評価) 値しかない場合、コンパイル時に評価されます。あなたの場合:2、、、(list 1 2)およびbla

私が知っているこれに対する唯一の解決策は、を使用することevalです。この特定の例は、次のように変更できます。

(defmacro testing (&optional var)
  `(eval (append '(list 'this 'is)  
                 (when (consp ',var)
                   '('a 'list))))

しかし、あなたは同意すると思いますが、それは本当に醜いです。また、字句変数を使用したい場合は機能しません。通常、問題を再定式化する方法があるため、そのような倒錯は必要ありません。

于 2012-02-09T17:07:32.667 に答える