function の役割り

IIJ技術研究所 山本和彦
作成:2002/08/28
更新:2002/08/30

関数をクオートするのには quote (') より function (#') の方がよいとされている。 しかし、どういう利点があるのかあまり理解されていない。

C 言語のソースを見ると、quote と function はまったく同じ実装になっている。 つまり、実行時の役割は完全に一緒である。 以下の例では、auto-fill-function をいうシンボルをクオートしている。 このようにシンボルをクオートする場合は、 「以下のシンボルは関数ですよ」という「コメント」としての役割はあっても、 クオートという意味においてはまったく違いはない。

(setq auto-fill-function (function my-auto-fill-function))

では何が嬉しいのか? それは、byte compile のときに、 quote でクオートするときよりも適切に byte compile ができる可能性があることである。 より適切に byte compile されるのは、 以下の条件が揃ったときに限る。

つまり、byte compiler が匿名関数だと判断できない場合に、 プログラマが function でクオートすることで関数だと明記しておけば、 匿名関数の内部まで byte compile できるというだけのことだ。

以下の例は、匿名関数の内部は byte compile されていない。 これは lambda の部分が匿名関数なのか、 単なるリストなのか、 「単純」には byte compiler が判断できないためである。

(defun foo (lst)
  (let ((plus2 '(lambda (x) (+ x 2))))
    (mapcar plus2 lst)))

(byte-compile 'foo)
→ #[(lst) "\302^X\303^H        \")\207" [plus2 lst (lambda (x) (+ x 2)) mapcar] 3]

だから、function でクオートすることで、 byte compiler へ関数だと教えれば、 匿名関数の内部まで byte compile される。

(defun bar (lst)
  (let ((plus2 #'(lambda (x) (+ x 2))))
    (mapcar plus2 lst)))

(byte-compile 'bar)
→  #[(lst) "\302^X\303^H        \")\207" [plus2 lst #[(x) "^H\301\\\207" [x 2] 2] mapcar] 3]

しかし、quote でクオートされていても単純に関数だと分る場合は、 匿名関数の内部まで byte compile される。 以下のように、mapcar の第一引数となっていれば、 lambda の部分が関数なのは明らかだから、 匿名関数の内部まで byte compile される。

(defun baz (lst)
  (mapcar '(lambda (x) (+ x 2)) lst))

(byte-compile 'baz)
→ #[(lst) "\301\302^H\"\207" [lst mapcar #[(x) "^H\301\\\207" [x 2] 2]] 3]

「単純」に分る部分については、 byte compile の前に処理されている。 bytecomp.el には以下のようなコードがある。

(byte-defop-compiler-1 apply byte-compile-funarg)
(byte-defop-compiler-1 mapcar byte-compile-funarg)
(byte-defop-compiler-1 mapatoms byte-compile-funarg)
(byte-defop-compiler-1 mapconcat byte-compile-funarg)
(byte-defop-compiler-1 mapc byte-compile-funarg)
(byte-defop-compiler-1 sort byte-compile-funarg-2)

たとえば第一行は、 apply の前処理として byte-compile-funarg を呼び出す設定である。 byte-compile-funarg は、 第一引数が匿名関数かつ quote でクオートされていれば、 function でクオートし直す。

さらに驚くべきことに、実は lambda はクオートする必要がない。 なぜなら、subr.el で lambda は (function (lambda )) を返す マクロとして定義されているからだ。

(defmacro lambda (&rest cdr)
  (list 'function (cons 'lambda cdr)))

(macroexpand '(lambda (x) (+ x 2)))
→ (function (lambda (x) (+ x 2)))

だから lambda はクオートしないのが、 記述量が少なく、function に展開されて byte compile の効率も上がるので、 よい記述方法だと言える。

(defun goo (lst)
  (let ((plus2 (lambda (x) (+ x 2))))
    (mapcar plus2 lst)))

(byte-compile 'goo)
→  #[(lst) "\302^X\303^H        \")\207" [plus2 lst #[(x) "^H\301\\\207" [x 2] 2] mapcar] 3]

というわけで function が役に立つ局面は、 実際問題としては少ない。


謝辞:lambda がマクロであることは、土屋雅稔さんに教えて頂いた。