#:g1: LispWorks: Adviceの紹介

Posted 2014-09-04 14:15:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の247日目です。

LispWorks: Adviceとはなにか

 LispWorks: Adviceは、LispWorksが提供するCommon LispでAdvice機能が使える拡張です。

パッケージ情報

パッケージ名LispWorks: Advice
ドキュメンテーション 6 The Advice Facility

インストール方法

 LispWorksに標準で添付されてきます。defadviceは、lispworks(lw)パッケージに属していますが、cl-userからも使えるようになっています。

試してみる

(matu 8)
;>> >>8<<
;=> NIL
           

のような関数があったとすると、before、after、aroundを全部付けた関数は、

(defadvice (matu around0 :around) (n)
  (prog2 (write-line "around0 ==>")
         (call-next-advice n)
         (write-line "around0 <==")))

(defadvice (matu around1 :around) (n) (prog2 (write-line "around1 ==>") (call-next-advice n) (write-line "around1 <==")))

(defadvice (matu before0 :before) (n) (write-line "before0:"))

(defadvice (matu before1 :before) (n) (write-line "before1:"))

(defadvice (matu after0 :after) (n) (write-line "after0:"))

(defadvice (matu after1 :after) (n) (write-line "after1:"))

(matu 8) ;>> around1 ==> ;>> around0 ==> ;>> before1: ;>> before0: ;>> >>8<< ;>> after0: ;>> after1: ;>> around0 <== ;>> around1 <== ;=> NIL

こんな感じの動作になります。
後で追加したものの方がより外側に適用されますが、aroundではcall-next-adviceを使って本体を呼び出すことになります。大体のところはCLOSの標準のメソッド結合と同じ感覚ですね。

 Adviceの削除には、delete-adviceとremove-adviceがありますが、delete-adviceだとクォートがいりません。

(delete-advice matu after1)

 defadviceはマクロとメソッドにも使えて、マクロだと展開をフックすることになり、

(defmacro mydefun (name (&rest args) &body body)
  `(defun ,name (,@args) ,@body))

(defadvice (mydefun inline :around) (form env) (destructuring-bind (def name args &body body) form (declare (ignore def args body)) `(progn (declaim (inline ,name)) ,(call-next-advice form env))))

(mydefun foo (n) n) ;===> (PROGN (DECLAIM (INLINE FOO)) (DEFUN FOO (N) N))

メソッドの方は、どれに特定化するかを指定可能です。

(defmethod bamatu (x y) t)

(defmethod bamatu ((x integer) (y list)) (list x y))

(bamatu 1 1) ;=> T

(bamatu 1 '(1 2 3)) ;=> (1 (1 2 3))

(defadvice ((method bamatu (integer list)) type-annot :around) (x y) (destructuring-bind (x y) (call-next-advice x y) `(:integer ,x :list ,y)))

(bamatu 1 1) ;=> T

(bamatu 1 '(1 2 3)) ;=> (:INTEGER 1 :LIST (1 2 3))

まとめ

 今回は、LispWorks: Adviceを紹介してみました。
Advice機構は古の1970年代のINTERLISPから存在しますが、一度、歴代のAdvice機構をサポートする処理系を並べて比較してみたいところです。

comments powered by Disqus