1 つの定数値を返す関数をオンザフライで作成しようとしています。
JavaScript やその他の最新の命令型言語では、クロージャーを使用します。
function id(a) {
return function() {return a;};
}
しかし、Emacs Lisp はそれらをサポートしていません。
恒等関数と部分関数のアプリケーションを組み合わせて作成できますが、どちらもサポートされていません。
では、どうすればいいですか?
lexical-let で別の解決策を見つけました
(defun foo (n)
(lexical-let ((n n)) #'(lambda() n)))
(funcall (foo 10)) ;; => 10
Emacsの本物の(偽物ではない)クロージャー24。
変数lexical-bindingの値がtの場合、Emacs 24には字句スクープがありますが、defun特殊形式は、字句的にバインドされたコンテキストでは正しく機能しません(少なくとも、Emacs 24.2.1では)。本物の(偽物ではない)クロージャーを定義します。例えば:
(let ((counter 0))
(defun counting ()
(setq counter (1+ counter))))
defunのシンボルカウンターは、その名前のグローバル変数(存在する場合)にバインドされ、 letで定義されている字句変数ではないため、期待どおりに機能しません。関数カウントが呼び出されたときに、グローバル変数が存在しない場合、それは明らかに失敗します。ただし、そのようなグローバル変数がある場合は更新されますが、これはおそらく意図されたものではなく、関数が正しく機能しているように見える可能性があるため、バグを追跡するのが難しい可能性があります。
このようにdefunを使用すると、バイトコンパイラは警告を出します。おそらく、この問題はEmacsの将来のバージョンで解決されるでしょうが、それまでは次のマクロを使用できます。
(defmacro defun** (name args &rest body)
"Define NAME as a function in a lexically bound context.
Like normal `defun', except that it works correctly in lexically
bound contexts.
\(fn NAME ARGLIST [DOCSTRING] BODY...)"
(let ((bound-as-var (boundp `,name)))
(when (fboundp `,name)
(message "Redefining function/macro: %s" `,name))
(append
`(progn
(defvar ,name nil)
(fset (quote ,name) (lambda (,@args) ,@body)))
(if bound-as-var
'nil
`((makunbound `,name))))))
カウントを次のように定義する場合:
(let ((counter 0))
(defun** counting ()
(setq counter (1+ counter))))
期待どおりに機能し、呼び出されるたびに字句的にバインドされた変数カウントを更新し、新しい値を返します。
警告:字句的にバインドされた変数の1つと同じ名前の関数を無効にしようとすると、マクロは正しく機能しません** 。つまり、次のようなことをした場合:
(let ((dont-do-this 10))
(defun** dont-do-this ()
.........
.........))
誰かが実際にそれをしているとは想像できませんが、言及する価値がありました。
注:clパッケージのマクロdefun *と衝突しないように、マクロdefun ** という名前を付けましたが、そのパッケージにはまったく依存していません。
ばかげた考え: どうですか:
(defun foo (x)
`(lambda () ,x))
(funcall (foo 10)) ;; => 10
Emacs 24 には字句バインディングがあります。