他の人のEmacs Lispの設定を眺めていて気づいたのですが、(add-hook hoge-hook XXXX)のXXXX部分にlambdaを入れる場合、

(lambda () ...)

と普通に書く人と、

'(lambda () ...)

みたいにクオートして書く人と、

#'(lambda () ...)

みたいな謎クオートする人がいますよね。

このへんのうち、実際どのやり方が正しくてどれが間違っているのかよく知らなかったので、Emacs Lispにおける関数について調べてみました。



Emacs LispはいわゆるLisp-2なので、変数と関数は別々の名前空間に存在します。

(global-set-key (kbd "C-p") previous-line) ; NG!!
;; => Symbol's value as variable is void: previous-line

(global-set-key (kbd "C-p") 'previous-line) ; OK!!

関数名から関数自身を取得するにはsymbol-functionを使用し、関数名を指定して呼び出すにはfuncallを使用します。

(defun print-hoge (fuga)
  (message "hoge %s" fuga))

(symbol-function 'print-hoge)
;; => (lambda (fuga) (message "hoge %s" fuga))

(funcall 'print-hoge "fuga")
;; => hoge fuga

しかし、symbol-functionで手に入れた関数本体をそのまま呼び出せるかといえば、そういうわけでもないみたいです。

((symbol-function 'print-hoge) "fuga")
;; => Invalid function: (symbol-function (quote print-hoge))

エラーメッセージから察するに、S式の関数に相当する部分を評価せずに扱っているようです。
この関数部分がシンボルで、それが実際に存在する関数の名前であるか、もしくはリストで、それが正しいラムダ式を表していれば関数として実行しているっぽいです。

((lambda (x) x) 1)
;; => 1

で、このlambdaが曲者。

(lambda (x) x)
;; => (lambda (x) x)

(lambda hoge)
;; => (lambda hoge)

(lambda)
;; => (lambda)

lambda自体はマクロになっていて、「引数全体をクオートしたリストの頭にlambdaをくっつけて返す」ものになっています。要するに(lambda ...)という形のS式をクオートしてもしなくても同じような式になるようになっています。

;; 要するにこんな感じ
(defmacro fun (&rest body)
  `(quote (fun ,@body)))

(fun (x) x)
;; => (fun (x) x)

これのfunを全部lambdaに変えたようなことをやっています。

そして、もう一つ重要なのは、Emacs Lispは「頭が'lambdaであるようなリスト」を関数とみなして実行してしまうことです。

(funcall '(lambda (x) x) 1)
;; => 1

たぶんバイコンパイルとかされたら一人前の関数になってくれるんじゃないかと思いますが[要出典]、基本的に関数はただのリストっぽいです。ただのリストなのでクロージャとかいう概念もありません*1

(defun make-counter ()
  (let ((n 0))
    (lambda ()
      (setq n (1+ n))
      n)))
(defvar counter (make-counter))
(listp counter) ; => t
(funcall counter)
;; => Symbol's value as variable is void: n

で、本題。
lambdaの頭に付けるクオートのうちどれが適切なのかという話ですが、これは#'でクオートするのが正しいようです。

GNU Emacs Lisp Reference Manual: Anonymous Functions

上のドキュメントによると、#'はほぼ'と同様のクオートですが、処理系に「これは関数だよ」と教える機能があるそうです。処理系はそれを元に、#'でクオートされているラムダ式が「実際に関数」であるのか「たまたま頭がlambdaだっただけのリスト」なのかを判断し、前者であればいい感じにバイコンパイルしてくれたりするそうです。

*1:余談ですが、Emacs24以降はlexical bindingをサポートしているようなので、クロージャもどうにかすれば作れるらしいです。