#:g1: Clozure CL: Advisingの紹介

Posted 2014-09-11 01:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の254日目です。

Clozure CL: Advisingとはなにか

 Clozure CL: Advisingは、Clozure CLが提供するアドバイス機構です。

パッケージ情報

パッケージ名Clozure CL: Advising
ドキュメントClozure CL Documentation: Advising

インストール方法

Clozure CLの標準で利用可能で、CCLパッケージで定義されていますが、cl-userでも最初から利用できるようになっています。

試してみる

 用意されているのは、

です。大抵は、advi*c*eですが、Clozure CLでは、advi*s*eというところが注意点です。ややこしい。
adviseはマクロで、ボディの中では、arglistで元の関数の引数リストが参照可能。また、returnでボディから抜けることも可能です。

(advise foo (if (some #'(lambda (n) (not (numberp n))) arglist)
	      (return 0))
	:when :before :name :zero-if-not-nums)

 こんな関数があったとすれば、

(defun matu (x)
  (princ x)
  (terpri))

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

こんな感じで使えます。

(advise matu
        (prog2 (write-line "around0 ==>")
               (:do-it)
               (write-line "around0 <=="))
        :when :around
        :name around0)

(advise matu (prog2 (write-line "around1 ==>") (:do-it) (write-line "around1 <==")) :when :around :name around1)

(advise matu (write-line "before0:") :name before0 :when :before)

(advise matu (write-line "before1:") :when :before :name before1)

(advise matu (write-line "after0:") :when :after :name after0)

(advise matu (write-line "after1:") :when :after :name after1)

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

 またメソッドにも適用可能です。

(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))

(advise (:method bamatu (integer list)) (destructuring-bind (x y) (:do-it) `(:integer ,x :list ,y)) :when :around :name type-annot)

(bamatu 1 1) ;=> T

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

 LispWorksやAllegro CLのようにマクロには適用できませんが、マクロ展開関数に適用すれば、できないこともないですね。

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

(setf (fdefinition 'mydefun-expander) (macro-function 'mydefun))

(advise mydefun-expander (destructuring-bind (def name args &body body) (first arglist) (declare (ignore def args body)) `(progn (declaim (inline ,name)) ,(:do-it))) :when :around :name inline)

(setf (macro-function 'mydefun) (fdefinition 'mydefun-expander))

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

まとめ

 今回は、Clozure CL: Advisingを紹介してみました。
ここ最近Advice機能を比較している感じですが、微妙に似ていつつも微妙に違いますね。

comments powered by Disqus