2

マクロと関数の違いについて混乱しています。具体的には、PART ONE が成功したのに、以下の PART TWO が失敗した理由です。

(defun foo () "foo")
(setf a 3) ;; sets the symbol value cell to 3
(setf a #'foo) ;; PART ONE
(funcall a) ;; returns foo

(defmacro bar () "bar")
(setf b #'bar) ;; Error the macro name bar was found as an argument to function PART TWO
4

4 に答える 4

7

マクロは関数ではありません。したがって、マクロ名から関数オブジェクトを取得することはできません。関数は適用できますが、マクロは適用できません。

マクロはソース コードを想定し、新しいソース コードを生成します。

Common Lisp は、実行前のコンパイル時にこれを実行できるように定義されています。一般的な場合、Common Lisp は実行時マクロ展開をサポートしていません。Common Lisp は、実行前にコードを完全にコンパイルできるようにするためにこれを行います。Common Lisp を定義する際の目標の 1 つは、大規模な Lisp プログラムを効率的に実行できる言語として定義することでした。ランタイム コード生成は、制御された方法でのみ有用です。そうしないと、まったく新しいクラスの実行エラーが実行時に発生する可能性があります。一般的なランタイム コード操作を可能にするマクロ メカニズムは、望ましくないと見なされていました。

古い Lisp 方言には、実行時に呼び出すことができ、実行時にソースを操作できるマクロのようなものである、いわゆるFEXPRのアイデアがありました。この機能は、Common Lisp では削除されました。この背景については、Kent Pitmanの Special Forms in Lispを参照してください。

于 2012-11-15T12:38:21.803 に答える
3

( #sharpsign)は、ディスパッチ マクロ文字である標準マクロ文字です。別のキャラクターと合成することになっています。( #'sharpsign 単一引用符)の組み合わせは、その後に関数名またはラムダ式が必要であり、 に展開され(function expression)ます。

したがって、#'fooは読み取り時に に展開されます(function foo)fooが関数の場合、functionそれを評価します。レキシカルスコープでは、またはfooによる fboundである可能性があります。そのようなレキシカル定義がない場合、シンボルの関数からグローバル関数定義を取得しようとします。fletlabels

現在、レキシカルであれグローバルであれ、マクロを表す(function bar)ときにエラーを通知します。ただし、グローバル マクロのマクロ関数を取得するために使用することはできます。存在する場合は、フォームと環境の 2 つの引数の関数です。barmacroletdefmacro(macro-function 'bar)bar

のマクロ関数をフォームに適用しない限りbar、それはおそらくあなたが望むものではありません。のマクロ関数を適用することを考えてみましょうand: 論理ブール演算は実行されません。おそらく、指定されたフォームがif.

ただし、これが必要な場合macro-functionは、2 番目のオプションのパラメーターである環境があることに注意してください。defmacroまたは の引数として環境を取得できますdefine-setf-expander。後者の場合、通常get-setf-expansion、サブフォームを展開する際に字句環境を考慮に入れる必要があります。

これを試してください:

(funcall (macro-function 'and) '(and form1 form2 form3) nil)

演習: 独自のmacroexpand-1と をmacroexpand実装します。

演習: Common Lisp の特殊演算子を認識して、サブフォームに再帰するa macroexpand-all、 aを実装します。macroexpand

注: を使いすぎないでくださいmacroexpand-all。実装固有のコード ウォーカーが必要です。

于 2012-11-16T00:14:50.433 に答える
1

この理由は、マクロは関数ではないため、マクロを関数として参照することはできず (は、シンボルに対応する関数オブジェクトを取得する#'fooの省略形です)、それらを参照することもできません。(function foo)foofuncall

(setf b (lambda () (bar)))部分的な解決策は、同様に機能する関数でマクロをラップすることfuncallです。ただし、マクロに&rest/引数が必要な場合は機能しません。&bodyこの場合、あなたが望むものを達成するための一般的な方法はありません。したがって、アプローチを再考する必要があります。問題は、なぜfuncallマクロをしようとしているのかということです。たぶん、あなたの場合は通常の機能で十分でしょうか?

于 2012-11-15T09:18:36.753 に答える
0

それは「コンパイラプラグイン」としてのマクロの事に役立つかもしれません。さて、コンパイラの一部を変数に格納することは理にかなっていますか?いいえ(Lispでもありません)。

于 2012-11-16T10:08:41.113 に答える