Next: , Previous: , Up: 関数   [Contents][Index]


13.7 無名関数

関数は通常はdefunにより定義されて、同時に名前が与えられますが、明示的にラムダ式を使う — 無名関数(anonymous function)のほうが便利なときもあります。無名関数は名前つき関数が有効な場所ならどこでも有効です。無名関数は変数や関数の引数に割り当てられることがよくあります。たとえばある関数をリストの各要素に適用するmapcarfunction引数に渡すかもしれません(関数のマッピングを参照)。現実的な例はdescribe-symbols exampleを参照してください。

無名関数として使用するためのラムダ式を定義するとき、原則的にはリストを構築する任意の手法を使用できます。しかし通常はマクロlambda、スペシャルフォームfunction、または入力構文#'を使用するべきです。

Macro: lambda args [doc] [interactive] body…

このマクロは引数リストargs、(もしあれば)ドキュメント文字列doc、(もしあれば)インタラクティブ指定interactive、およびbodyで与えられるbodyフォームをもつ無名関数をリターンする。

ダイナミックバインディングの下では、このマクロはlambdaフォームを効果的に“自己クォート(self-quoting)”する。つまりCARlambdaであるようなフォームはフォーム自身を得る。

(lambda (x) (* x x))
     ⇒ (lambda (x) (* x x))

レキシカルバインディングの下で評価した際には、結果はクロージャオブジェクトになることに注意(クロージャーを参照)。

lambdaフォームは別の1つの効果をもつ。このマクロはfunction(以下参照)をサブルーチンとして使用することにより、Emacs評価機能(Emacs evaluator)とバイトコンパイラーに、その引数が関数であることを告げる。

Special Form: function function-object

このスペシャルフォームは評価を行わずにfunction-objectをリターンする。この点ではquote(クォートを参照)と似ている。しかしquoteとは異なり、Emacs評価機能とバイトコンパイラーに、これを関数として使用する意図を告げる役割をもつ。function-objectが有効なラムダ式と仮定すると、これは2つの効果をもつ:

  • そのコードがバイトコンパイルされているとき、function-objectはバイトコード関数オブジェクトにコンパイルされる(バイトコンパイルを参照)。
  • レキシカルバインドが有効ならfunction-objectはクロージャーに変換される。クロージャーを参照のこと。

function-objectがシンボルかつバイトコンパイル済みコードの場合には、その関数が未定義、あるいは実行時に認識されていなければバイトコンパイラーは警告を発する。

入力構文#'functionの使用の略記です。以下のフォームは等価です:

(lambda (x) (* x x))
(function (lambda (x) (* x x)))
#'(lambda (x) (* x x))

以下の例では3つ目の引数に関数をとるchange-property関数を定義して、その後のchange-propertyで無名関数を渡してこれを使用しています:

(defun change-property (symbol prop function)
  (let ((value (get symbol prop)))
    (put symbol prop (funcall function value))))

(defun double-property (symbol prop)
  (change-property symbol prop (lambda (x) (* 2 x))))

lambdaフォームをクォートしていないことに注意してください。

上記のコードをコンパイルすると無名関数もコンパイルされます。リストをクォートすることにより無名関数を構築した場合にはコンパイルはされません。

(defun double-property (symbol prop)
  (change-property symbol prop '(lambda (x) (* 2 x))))

この場合、無名関数はコンパイルされたコード内のラムダ式に保持されます。バイトコンパイラーはchange-propertyが関数としての使用を意図していることを知ることができないので、たとえこの関数が関数のように見えるとしても、このリストが関数であると決め込むことができません。