noflet 20141102.654(in MELPA)
locally override functions

概要

nofletflet の強力版で、ローカル関数を定義するマクロです。

Emacs Lispにおけるローカル関数といえば、
cl-fletcl-labelscl-letfdflet (要 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

本サイト内の関連パッケージ


本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。