コンパイル時に使用するすべてのインスタンスで展開する必要があるマクロがあります。コードベースを通過して各呼び出しを慎重にラップすることなく、これを指定する方法はありますeval-when-compile
か?
コンパイル時に使用するすべてのインスタンスで展開する必要があるマクロがあります。コードベースを通過して各呼び出しを慎重にラップすることなく、これを指定する方法はありますeval-when-compile
か?
回答:
バイトコンパイラが到達可能なすべてのマクロは、コンパイル中に展開されます。「到達可能」とは、本質的に引用されていないことを意味します。
defun
s、defmacro
s、lambda
s の本体は、それらを含むソースファイルがバイトコンパイルされると、すべてバイトコンパイルされます。そのため、引用符('
)内にない限り、マクロ内のマクロは展開されます。よくある間違いは、lambda
sを引用符で囲むことです。実際、sを引用符で囲むlambda
べきではありません。
これはマクロの大きな利点の1つです。よく書かれている限り、ランタイムのパフォーマンスには影響しません。他の利点は、もちろんその力と汎用性です。欠点は、オブジェクトではなく構文を操作していることです。そのため、問題が発生する余地が多くあります。
マラバルバがすでに説明したように、マクロはバイトコンパイル中に展開されます。ファイルがコンパイルされていない場合、ファイルのロード時にマクロが展開されます(積極的なマクロ展開)。
ただし、これに依存しないでください。それは非常に悪いスタイルです。通常、マクロを使用するコードが実際にコンパイルされることを期待することはできません。通常、コンパイル中はできるだけ少ないコードを実行する必要があります。特に、他の方法がない場合にのみ、マクロをほとんど使用しないでください。経験則として、構文にのみマクロを使用し、セマンティクス(または機能)には決して使用しないでください。
マクロは漏れやすい抽象化です。それらの拡張は、コンパイル時にターゲットコードにハードコーディングされており、遡って変更することはできません。その後、ターゲットコードは、展開時のマクロの特定の実装に依存します。具体的には、マクロ本体で使用されるすべての内部APIに依存します。
したがって、マクロに対してコンパイルされたコードを壊すことなく、このAPIやマクロ展開が依存するものを変更することはできません。
機能性のためのマクロのリベラルな使用は、依存性地獄への道を開きます。