1

私は今私を混乱させる次のコードを持っています.違いとこれを修正する方法を教えてくれることを願っています.

(defmacro tm(a)
   `(concat ,(symbol-name a)))

(defun tf(a)
       (list (quote concat) (symbol-name a)))

私はそれらが同じ効果であるべきだと思うだけですが、実際にはそうではないようです.
私は次の呼び出しを試みます:

CL-USER> (tf 'foo)
(CONCAT "FOO")

CL-USER> (tm 'foo)
value 'FOO is not of the expected type SYMBOL.
[Condition of type TYPE-ERROR]

だから問題は何ですか?

私が欲しいのは:

(tm 'foo)  ==>  (CONCAT "FOO")
4

2 に答える 2

4

最初の問題は、'fooがリーダーによって に展開されることです(quote foo)。これは、シンボルではなくリストです。マクロは展開を試み(tm (quote foo))ます。リスト(quote foo)はパラメータとしてaマクロ展開関数に渡され、マクロ展開関数はそのsymbol-name. リストは の有効な引数ではありませんsymbol-name。したがって、マクロ展開は失敗します。

2 番目の問題は、(tm foo)(note: no quote) はに展開され(concat "FOO")ますが、このフォームは REPL によって実行されるため、これも関数と同じではありませんtf。もちろん、マクロは関数とは異なることを行うため、これは驚くべきことではありません。

于 2011-07-01T13:25:59.867 に答える
2

まず、注意してください

`(concat ,(symbol-name a))

(list (quote concat) (symbol-name a))

まったく同じことをします。これらは同等のコードです(逆引用符の構文はマクロ本体に限定されません!):どちらも、最初の要素がシンボルCONCATで、2番目の要素が変数が参照するシンボル名であるリストを作成Aします。

明らかに、これはA、Svanteが指摘したように、マクロ呼び出しの例では当てはまらないシンボルを参照する場合にのみ意味があります。

もちろん、リストからシンボルを抽出することもできます(QUOTE FOO)が、その場合、次のようにマクロを呼び出すことはできません。

(let ((x 'foo))
  (tm x))

これは、マクロのユーザーに、とにかくリテラル定数である必要があるシンボルを明示的に引用するように強制したい理由の問題を提起します。

次に、マクロの動作は次のとおりです。マクロは引数としてコードの一部(など(QUOTE FOO))を取り、マクロの拡張時に(多かれ少なかれ)ソースコードのマクロ呼び出しを置き換える新しいコードを生成します。生成されたコード内でマクロ引数を再利用すると、マクロ引数を後で評価する場所(次のように)に配置すると便利なことがよくあります。

(defmacro tm2 (a)
  `(print (symbol-name ,a)))

letこのコードが何をするのか、そして上記の私の例が今うまくいくかどうかを考えてください。それはあなたを正しい軌道に乗せるはずです。

最後に、アドバイスの一部です。関数が機能する場合はマクロを避けてください。これにより、実装者とユーザーの両方の作業がはるかに楽になります。

于 2011-07-01T15:09:19.390 に答える