#:g1: FlavorsのdefwrapperとCommon Lispの:aroundの比較

Posted 2018-12-14 14:48:47 GMT

Lisp メソッドコンビネーション Advent Calendar 2018 14日目 》

Flavorsには、Common Lispのメソッドコンビネーションの:aroundが無いようなのですが、その代わりにdefwrapperという構文があったようです。

defwrapperの発展的解消の結果、:aroundに纏められたのかなと思えてきたのですが、CADRのエミュレータ上でdefwrapperの実際の使い勝手と挙動を確認してみることにしました。

挙動確認のお題ですが、先日のstandardメソッドコンビネーションの説明で:before:after、primary、:around全部盛りの定義を紹介したものをFlavorsに書き換えて試してみます。

Flavorsは、(CADR System 78.48 (1982年あたり))のものです。

(progn
  (defflavor f1 () ())
  (defflavor f2 () (f1))
  (defflavor f3 () (f2)))

(progn (defmethod (f1 foo) () (format T "~16T~A~%" '(foo f1))) (defmethod (f2 foo) () (format T "~16T~A~%" '(foo f2)) (funcall #'(:method f1 foo) self)) (defmethod (f3 foo) () (format T "~16T~A~%" '(foo f3)) (funcall #'(:method f2 foo) self)) ;; (defmethod (f1 :before foo) () (format T "~8T~A~%" '(foo f1 :before))) (defmethod (f2 :before foo) () (format T "~8T~A~%" '(foo f2 :before))) (defmethod (f3 :before foo) () (format T "~8T~A~%" '(foo f3 :before))) ;; (defmethod (f1 :after foo) () (format T "~24T~A~%" '(foo f1 :after))) (defmethod (f2 :after foo) () (format T "~24T~A~%" '(foo f2 :after))) (defmethod (f3 :after foo) () (format T "~24T~A~%" '(foo f3 :after))))

(progn (defwrapper (f3 foo) (() . body) `(progn (format T "~A~%" '(foo f3 :wrapper)) . ,body))

(defwrapper (f2 foo) (() . body) `(progn (format T "~A~%" '(foo f2 :wrapper)) . ,body))

(defwrapper (f1 foo) (() . body) `(progn (format T "~A~%" '(foo f1 :wrapper)) . ,body)))

(<- (make-instance 'f3) 'foo)(FOO F3 WRAPPER)(FOO F2 WRAPPER)(FOO F1 WRAPPER)(FOO F3 BEFORE)(FOO F2 BEFORE)(FOO F1 BEFORE)(FOO F3)(FOO F2)(FOO F1)(FOO F1 AFTER)(FOO F2 AFTER)(FOO F3 AFTER)
→ NIL

思えば、Flavorsには、call-next-methodのようなものがない気がするのですが、とりあえず、Common Lispと違ってfunctionの記法が拡張されているので、(funcall #'(:method f2 foo) self) という風にメソッドを直接起動してしのいでいます。

後期のFlavorsや、New Flavorsにはあるのかもしれません。
そもそもFlavorsは標準規格化されてないので、実装によりAPIや挙動がまちまちなので確認が、ちょっとしんどいです。

上記のコードをみて分かるかと思いますが、:aroundの中で、call-next-methodを呼ぶのではなく、defwrapperでは、メソッドのコードをマクロで包み込む、という感じになります。

また、defwrapperはマクロではありますが、Flavorを指定できるので、どのメソッドの外周を包むかを:aroundと同じく指定することが可能です。

まとめ

defwrapper:aroundに置き換わったと考えると、Common Lispのメソッドコンビネーションの動作の謎が解ける気がして、Flavorsのdefwrapperを紹介してみました。

後期Flavors、New Flavors、さらに、defwrapper以外の謎構文、defwhopperとメソッドコンビネーションについても調べて纏めてみたいと思っています。


HTML generated by 3bmd in LispWorks 7.0.0

comments powered by Disqus