🤖

Emacs 29 の Oclosure について

2022/12/19に公開

もうすぐリリースされる Emacs 29 には、従来の閉包 に「型」と「スロット」を付加したオープン閉包 (open closure) 機能が導入されるので紹介します。

従来の Emacs Lisp では、定義された関数における変数の値は実行時に動的に参照されていました(動的束縛)。しかし、2011年にリリースされた Emacs 24 からは、字句束縛 が導入され、 lexical-binding 変数が t のときに定義される関数は、関数定義時の字句環境を記録する閉包に変換されます。

しかし、従来の閉包は、外部から観測や操作ができない、不透明なオブジェクトでした。

Emacs 29 で導入された「オープン閉包 (Open Closure)」は、閉包にCLOSと同様の型とスロットを定義し、必要に応じてスロットの値を変更したり、関数の型をチェックすることを可能にします。

以下にオープン閉包の例を示します。

;; 引数に数を加えるオープン閉包 add-val を定義します。
;; 加える値をスロット val として定義し、後から変更できることを :mutable t で指定します。
(oclosure-define add-val "add val." (val :mutable t))
;; オープン閉包 add-val で、引数に1を加える関数 add-val1 を定義します。
(setq add-val1 (oclosure-lambda (add-val (val 1)) (arg) (+ arg val)))
;; add-val1 に引数15 を与えると、16を返します。
(funcall add-val1 15)
;; add-val1 の型が を add-val かをチェックします。
(cl-typep add-val1 'add-val)
;; add-val1 のスロット val の値を確認すると、1を返します。
(slot-value add-val1 'val)
;; スロット val の値を3へ変更します。
(setf (slot-value add-val1 'val) 3)
;; 関数を15を引数にして呼び出すと、18を返します。
(funcall add-val1 15)

Emacs Lisp では、関数をhook変数として指定する状況が多いため、引数に指定された関数の型検査など、様々な応用ができそうです。

オープン閉包については、作者が論文を出していますので、興味のある方は参照してください。

Discussion