- noflet 20141102.654(in MELPA)
- locally override functions
概要
noflet は flet の強力版で、ローカル関数を定義するマクロです。
Emacs Lispにおけるローカル関数といえば、
cl-flet 、 cl-labels 、 cl-letf 、 dflet (要 el-x パッケージ)
を使う方法があります。
しかし、ローカル関数で元の関数を再定義する場合、
退避する必要があるのでコードがぐちゃぐちゃになってしまいます。
その問題を解決するのが noflet マクロです。
noflet内での関数定義においては
変数 this-fn が元の関数定義を保持しているので、
(funcall this-fn 引数...)
という形で元の関数にアクセスできます。
関数ローカルな アドバイス みたいなものともいえます。
というわけで、関数が呼び出している関数の挙動が
気に入らない場合はローカルで上書きしちゃってください。
なお、インデントを正しくしてくれるコードもあるのですが、
僕の環境(Emacs 24.4)では正しくインデントしてくれませんでした。
インストール
パッケージシステムを初めて使う人は
以下の設定を ~/.emacs.d/init.el の
先頭に加えてください。
(package-initialize) (setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/") ("melpa" . "http://melpa.org/packages/") ("org" . "http://orgmode.org/elpa/")))
初めてnofletを使う方は
以下のコマンドを実行します。
M-x package-install noflet
アップグレードする方は、
以下のコマンドでアップグレードしてください。
そのためにはpackage-utilsパッケージが必要です。
M-x package-install package-utils (初めてアップグレードする場合のみ) M-x package-utils-upgrade-by-name noflet
使用例
dfletやcl-letfといった旧来の書き方と比較してみてください。
いかにすんなりと記述できるかがわかります。
(require 'noflet) ;;; 元の関数呼び出し (defun hoge (x) (+ x 100)) (defun fuga (x) (+ (hoge x) 1000)) (hoge 9) ; => 109 (fuga 9) ; => 1109 ;;; hogeを元の関数の結果に1足したものに置き換える (noflet ((hoge (x) (1+ (funcall this-fn x)))) (fuga 9)) ; => 1110 ;;; hogeを引数そのものを返すように置き換える (noflet ((hoge (x) x)) (fuga 9)) ; => 1009 ;;; dflet(元のflet)で元の名前で呼ぶと ;;; 再帰呼び出しになって無限ループになるので退避する必要ある (let ((orig-hoge (symbol-function 'hoge))) (dflet ((hoge (x) (1+ (funcall orig-hoge x)))) (fuga 9))) ; => 1110 ;;; cl-letfでも書けるが面倒 (cl-letf ((orig-hoge (symbol-function 'hoge)) ((symbol-function 'hoge) (lambda (x) (1+ (funcall orig-hoge x))))) (fuga 9)) ; => 1110 ;;; 参考:cl-fletではhogeで元の関数を呼んでしまう (cl-flet ((hoge (x) (1+ (hoge x)))) (fuga 9)) ; => 1109 ;;; nolexfletはcl-fletの別名だがインデントを調節してくれる (nolexflet ((hoge (x) (1+ (hoge x)))) (fuga 9)) ; => 1109
本サイト内の関連パッケージ
本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。