Next: declareフォーム, Previous: 関数の陳腐化の宣言, Up: 関数 [Contents][Index]
インライン関数(inline function)は関数と同様に機能しますが、1つ例外があります。その関数の呼び出しがバイトコンパイルされると(バイトコンパイルを参照)、その関数の定義が呼び出し側に展開されます。
インライン関数を定義するには、defunのかわりにdefsubstを記述するのがシンプルな方法です。定義の残りの部分は同一に見えますが、defsubstの使用によりバイトコンパイルにそれをインラインにするように指示します。
このマクロはインライン関数を定義する。マクロの構文はdefunとまったく同じ(関数の定義を参照)。
関数をインラインにすることにより、その関数の呼び出しが高速になる場合があります、が欠点もありその1つは柔軟性の減少です。その関数の定義を変更すると、すでにインライン化された呼び出しは、リコンパイルを行うまで古い定義を使用することになります。
もう1つの欠点は、大きな関数をインライン化することにより、コンパイルされたコードのファイル上およびメモリー上のサイズが増大することです。スピード面でのインライン化の有利性は小さい関数で顕著なので、一般的に大きな関数をインライン化するべきではありません。
インライン関数はデバッグ、トレース、アドバイス(Emacs Lisp関数にたいするアドバイスを参照)に際してうまく機能しません。デバッグの容易さと関数の再定義の柔軟さはEmacsの重要な機能なので、スピードがとても重要であってdefunの使用が実際に性能の面で問題となるのか検証するためにすでにコードをチューニングしたのでなければ、たとえその関数が小さくてもインライン化するべきではありません。
インライン関数を定義した後そのインライン展開はマクロ同様、同じファイル内の後の部分で処理されます。
インライン関数が実行するのと同じコードに展開されるマクロ(マクロを参照してください)を定義するためにdefmacroを使用できます。しかし式内でのマクロの直接の使用には制限があります
—
apply、mapcarなどでマクロを呼び出すことはできません。通常の関数からマクロへの変換には余分な作業が必要になります。通常の関数をインライン関数に変換するのは簡単です。defunをdefsubstに置き換えるだけです。インライン関数の引数はそれぞれ正確に1回評価されるので、マクロのときのようにbodyで引数を何回使用するかを心配する必要はありません。
かわりにコンパイラーマクロとしてインライン展開されるコードを記述することにより関数を定義できます(declareフォームを参照)。以下のマクロがこれを可能にします。
自身をインライン化するコードを提供することにより、コンパイラーマクロとして関数nameを定義する。この関数は引数リストargsを受け取り、指定されたbodyをもつ。
docが与えられたなら、それは関数のドキュメント文字列であること(関数のドキュメント文字列を参照)。declareが与えられたなら、それは関数のメタデータを指定するdeclareフォームであること(declareフォームを参照)。
define-inlineで定義された関数は、defsubstやdefmacroで定義されたマクロにたいして複数の利点をもちます。
mapcarに渡すことができる(関数のマッピングを参照)。
cl-defsubstより予測可能な方法で振る舞う(Argument Lists in Common Lisp
Extensions for GNU Emacs Lispを参照)。
defmacroと同様に、define-inlineでインライン化された関数は、呼び出し側からダイナミックかレキシカルいずれかのスコーピングルールを継承します。変数のバインディングのスコーピングルールを参照してください。
以下のマクロはdefine-inlineで定義された関数のbody内で使用する必要があります。
define-inlineにたいしてexpressionをクォートする。これはバッククォート(バッククォートを参照)と似ているが、コードをクォートして,だけを受け入れ、,@は受け入れない。
インライン関数の引数が正確に一度評価されて、ローカル変数を作成することを保証する便利な手段を提供する。
これはlet (ローカル変数を参照)と似ている。これはbindingsで指定されたようにローカル変数をセットアップしてから、それらのバインディングの効力の下にbodyを評価する。
bindingsの各要素はシンボル、または(var expr)という形式のリストであること。これはexprを評価して結果をvarにバインドする。しかしbindingsの要素がシンボルvarだけなら、varの評価結果はvarに再バインドされる(これはletの挙動と大きく異なる)。
bindingsの終端はnil、または引数リストを保持するシンボル。シンボルの場合には各引数を評価して、結果のリストがシンボルにバインドされる。
expressionの値が既知なら非nilをリターンする。
expressionの値をリターンする。
formatに応じてargsをフォーマットしてエラーをシグナルする。
以下はdefine-inlineを使用した例です:
(define-inline myaccessor (obj)
(inline-letevals (obj)
(inline-quote (if (foo-p ,obj) (aref (cdr ,obj) 3) (aref ,obj 2)))))
これは以下と等価です
(defsubst myaccessor (obj) (if (foo-p obj) (aref (cdr obj) 3) (aref obj 2)))