pythonでクラスメソッドがいくつかあるみたいなので, それをCLOSで...という流れでなのですが
http://docs.python.org/library/stdtypes.html#additional-methods-on-float
CLOSでクラスメソッドを定義するには, eql Specializerを利用するのでしょうか?
(defclass hoge () ())
(defclass piyo () ())
(defmethod fuga ((class standard-class))
'top-level)
(defmethod fuga ((class (eql (find-class 'hoge))))
'specified)
(fuga (find-class 'hoge)) ; => 'specified
(fuga (find-class 'piyo)) ; => 'top-level
CLOSでは, メタクラスにアクセスするのに, find-classを呼ばなくてはいけないので,
クラスメソッドの呼び出しがめんどうだなぁとおもうのですが,
こういうものでしょうか?
-- ryohei
python知らなさすぎるので勘ですが、
クラス渡してもインスタンスを渡しても動作すべし…な感じからすると
こういう感じで良いのかなぁ…と思いました。
(defclass hoge () ())
(defclass piyo () ())
(defmethod fuga ((class t))
'top-level)
(defmethod fuga ((class hoge))
'specified)
(defmethod fuga ((class symbol))
(fuga (make-instance class)))
あとは少し意味変わりそうだけど、clapのクラスの
インスタンスを入れた定数を必ず作るルールにするとか?
2010/12/7 Ryohei Ueda <gara...@gmail.com>:
--
佐野匡俊(SANO Masatoshi)
snm...@gmail.com
佐野です。
python知らなさすぎるので勘ですが、
クラス渡してもインスタンスを渡しても動作すべし…な感じからすると
こういう感じで良いのかなぁ…と思いました。
(defclass hoge () ())
(defclass piyo () ())
(defmethod fuga ((class t))
'top-level)
(defmethod fuga ((class hoge))
'specified)
(defmethod fuga ((class symbol))
(fuga (make-instance class)))
あとは少し意味変わりそうだけど、clapのクラスの
インスタンスを入れた定数を必ず作るルールにするとか?
> シンボル取っていいのなら、eql specializerでクラスメソッド作っておいて、
> (defmethod fuga ((class symbol))
> (fuga (find-class class)))
> でもいいんじゃないでしょうか。
これだと, class hierarchyが利用できませんね.
mopでごにょごにょすればできると思いますが...
> あと、世の中のOOな言語のクラスメソッドには、単にクラスを名前空間として
> 利用してるものもあるような。そういうのはパッケージでカバーできちゃいますね。
たしかに, 名前空間として利用されているのが多いですね.
しかし, これがいわゆるlispのパッケージシステムでカバーできるかは疑問です.
というのは, lispのパッケージシステムは入れ子ができない,
モジュールではないというところです
個人的にモジュールシステムはANSI specで足りてないと思うところですが,
pythonだと
hogeモジュールのfugaクラスのpiyoクラスメソッドの呼び出しは
hoge.fuga.piyo()
となりますが, この時コード上でモジュール(名前空間)とクラスの見分けがつかないことが
重要な気がしてます.
(hoge::fuga::piyo)と書ければいいのになぁと思います(Perlっぽい?)
CLOSでクラスメソッドを定義するときに, 定義が面倒になるのはオレオレマクロ
でどうにかできるので良いですが, 呼び出しに工夫が必要だと思ってます.
もはやリードマクロで良いのではないのかと思いはじめてます.
<hoge> => (find-class 'hoge)
-- ryohei
2010/12/7 Shiro Kawai <shiro...@gmail.com>:
確かに。継承を利用したいなら、インスタンス作るか、
継承関係を対応させたメタクラス階層を作るかしかないですね。
どっちもドメインを限定できるならありだと思います
(前者は、make-instanceが副作用なしで軽い、という前提、もしくはクラスメソッド
ディスパッチ用のインスタンスを常に一つ作っておける、という前提。後者は、
クラス定義を専用のマクロでやってもらえる、という前提。)
>> あと、世の中のOOな言語のクラスメソッドには、単にクラスを名前空間として
>> 利用してるものもあるような。そういうのはパッケージでカバーできちゃいますね。
>
> たしかに, 名前空間として利用されているのが多いですね.
> しかし, これがいわゆるlispのパッケージシステムでカバーできるかは疑問です.
> というのは, lispのパッケージシステムは入れ子ができない,
> モジュールではないというところです
Allegro CLの階層型パッケージ名はそれほどポータブルではないかな。
Read時に解決しなくちゃならないので移植は大掛かりになっちゃいそうですね。
> CLOSでクラスメソッドを定義するときに, 定義が面倒になるのはオレオレマクロ
> でどうにかできるので良いですが, 呼び出しに工夫が必要だと思ってます.
> もはやリードマクロで良いのではないのかと思いはじめてます.
>
> <hoge> => (find-class 'hoge)
これは継承を利用できないという点ではsymbol取ってディスパッチするのと
(効率以外)同じでは?
クラスメソッドの使われ方にもいくつかあると思うんで、
目的とするところによってマッピングが違うっていうのもありじゃないかとは思います。
単なる名前空間的に使ってるのなら、メソッドにさえする必要なくて、単なる関数で
パッケージとか命名規則で対応、
「クラスで共有する資源」にアクセスさせたいのならMOPでちゃんとやる、ってな具合に。
まあ、Pythonからの均一なマッピングを目指す、というのならその利点もわかるので、
具体的なユースケースをわかっている方がとりあえずえいやっと書いちゃって後で困ったら
ががっと書き直す、ってんで良いかと。
あ, たしかにそうですね. ちょっとメタな話で頭が混乱してますw
> クラスメソッドの使われ方にもいくつかあると思うんで、
> 目的とするところによってマッピングが違うっていうのもありじゃないかとは思います。
> 単なる名前空間的に使ってるのなら、メソッドにさえする必要なくて、単なる関数で
> パッケージとか命名規則で対応、
> 「クラスで共有する資源」にアクセスさせたいのならMOPでちゃんとやる、ってな具合に。
> まあ、Pythonからの均一なマッピングを目指す、というのならその利点もわかるので、
> 具体的なユースケースをわかっている方がとりあえずえいやっと書いちゃって後で困ったら
> ががっと書き直す、ってんで良いかと。
ふむふむ, なるほど.
メタクラスの階層を作る, というのはやり過ぎな感じがするので,
クラスメソッド --> symbolを引数に取って各クラス名でeql specializer
デフォルトのメソッドでは, クラス階層を考慮するようなのをmopでごにょごにょ
next-call-method的なものを別途用意する.
というのをやる, define-class-methodみたいなのを提供する
という感じでどうでしょうか?
名前空間的にのみ使われる, というのを"判断する"のは難しそう...という気がしてます.
-- ryohei
2010/12/7 Shiro Kawai <shiro...@gmail.com>:
> クラスメソッド --> symbolを引数に取って各クラス名でeql specializer
> デフォルトのメソッドでは, クラス階層を考慮するようなのをmopでごにょごにょ
適当ですが作ってみました. うーん, やりすぎでしょうか? とても遅そうです
(defmacro define-class-method-default (name arg)
;; arg => (class arg2 arg3 ...)
`(defmethod ,name ,arg
(let ((cpl (mapcar #'class-name
(closer-mop:class-precedence-list
(find-class ,(car arg))))))
;; search valid method...
(dolist (c (cdr cpl))
(let ((methods (compute-applicable-methods
(symbol-function ',name)
(cons c (list ,@(cdr arg))))))
(dolist (m methods)
(let ((specializers (closer-mop:method-specializers m)))
(if (typep (car specializers) ;the first argument
'closer-mop:eql-specializer)
(return-from ,name (funcall
(closer-mop:method-function m) (list ,@arg)
nil)))))))
(error "cannot find applicable method"))))
;; you can write like
;; (define-class-method foo ((self 'bar-class) arg2 arg3 ...) ...)
(defmacro define-class-method (name arg &rest forms)
`(defmethod ,name ((,(caar arg) (eql ',(cadr (car arg)))) ,@(cdr arg))
,@forms))
(defclass hoge () ())
(defclass fuga (hoge) ())
(defclass piyo () ())
(closer-mop:finalize-inheritance (find-class 'hoge))
(closer-mop:finalize-inheritance (find-class 'fuga))
(closer-mop:finalize-inheritance (find-class 'piyo))
(define-class-method-default my-classmethod (arg))
(define-class-method my-classmethod ((arg hoge)) 'hoge-method)
(my-classmethod 'hoge) ; => HOGE-METHOD
(my-classmethod 'fuga) ; => HOGE-METHOD
(my-classmethod 'piyo) ; => cannot find applicable method
-- ryohei
2010/12/7 Ryohei Ueda <gara...@gmail.com>:
たぶん効率の良い実装ではないですが,
こんなかんじでclap-builtinに追加してみようと思います
命名則でマッピング, という話ですが, 僕が理想だとおもっているのは,
pythonの入門ブログ記事などで紹介されてるような短いコードが,
一定のルールにしたがって左から右にCLに変換すると, (だいたい)実行出来る,
というものです.
そこでいくつかのクラスメソッドは(foo-module:bar-class.baz-method)で,
ほかのものは(foo-module:baz-method 'foo-module:bar-class)というように2種類の
マッピングができてしまうのを危惧しています.
という話を延長していくと, __eq__や__lt__も実装するという流れになる気がしますが,
それは:keyやら:testにするのがlispなやりかたじゃないか?と思ったりするので, かなり
恣意的です笑.
http://docs.python.org/reference/datamodel.html
-- ryohei
2010/12/8 Ryohei Ueda <gara...@gmail.com>:
私がmopで何とかする、と言った時にイメージしてたのはこんな感じでした。
https://gist.github.com/732333
clap-baseを継承したクラスには、対応する継承関係を持つメタクラスを自動的に作るようにして、
実行時のディスパッチ自体はシステムのメカニズムに任せます。
但し、
- ensure-class-using-classに:aroundをかぶせるのはポータブルではないかも。少なくともAllegro
ではpackage lockを切っておかないと警告が出る。
- clap-base由来のクラスの多重継承は考えてない (clap-baseを継承しないmixinは多重継承できるけど)
- clap-base由来で、かつ自前のmetaclassを使いたい場合の考慮がない
など、難点も多々あります。結局どう使いたいかですね。
2010/12/7 Ryohei Ueda <gara...@gmail.com>:
> 但し、
> - ensure-class-using-classに:aroundをかぶせるのはポータブルではないかも。少なくともAllegro
> ではpackage lockを切っておかないと警告が出る。
> - clap-base由来のクラスの多重継承は考えてない (clap-baseを継承しないmixinは多重継承できるけど)
> - clap-base由来で、かつ自前のmetaclassを使いたい場合の考慮がない
>
> など、難点も多々あります。結局どう使いたいかですね。
integerやstringなどのbuilt-inクラスは出来ればそのまま使いたい, というのがあります.
ですので, clap-baseを導入せずにできる方法を考えたいです.
-- ryohei
2010/12/8 Shiro Kawai <shiro...@gmail.com>:
https://gist.github.com/732960
関連
http://www.myunitsconverter.com/thread/1152082/Help%20creating%20CLOS%20meta%20classes
んー, mopは難しい
その場合のインスタンスは, classの継承関係を表現するオブジェクトとしてのみ
利用される
となると, メソッドディスパッチでりようされるclass-of(なのか?)だけかえすよう
な空のオブジェクトが作成出来れば万事解決な気がしてきました.
つまり, make-empty-instanceみたいなものが定義出来れば...
allocate-instanceするけどinitialize-instanceを呼ばない、とか?
(defclass fuga () ((a :initform (make-list 100000)) b c d))
のように:initformをあたえても, allocate-instanceではinitformは評価されないみたいです
(sbclで確認)
CL-USER> (describe (allocate-instance (find-class 'fuga)))
#<FUGA {1003239481}>
[standard-object]
Slots with :INSTANCE allocation:
A = #<unbound slot>
B = #<unbound slot>
C = #<unbound slot>
D = #<unbound slot>
なので, これを利用するのが良いのではないか?と思います
built-inなクラスについては種類が限られてるからあらかじめインスタンス作ってテーブルに
しておけばいいし。
2010/12/7 Ryohei Ueda <gara...@gmail.com>:
イメージはこんな感じです
https://gist.github.com/733636
ここで問題なのは, CLのintegerクラスは, そのインスタンスが存在し
ないのでテーブルを作ることが困難です.
file-streamも(CLAPでクラスメソッドを定義するかはわかりませんが)
ファイルをオープンしないと作れないので難しいですね.
んー, もうちょっと考える必要がありそうです
integerに関しては, clap側でこのテーブルを作るためだけにクラスを一つ
導入するのかもしれないな, と思っています.
integer > fixnum
integer > bignum
integer > clap-integer
のように階層を作って, (allocate-instance 'clap-integer)してもよいのかもし
れませんが, ポータブルじゃない気もしています
(具体的なユースケースが揃ってからの方が考えやすいってことなので、
既にユースケースがあってそれの実現方法で悩んでるなら無視してください)
2010/12/8 Ryohei Ueda <gara...@gmail.com>:
スレッドも細かくは追えていないのと,
僕はPythonについて全く知らないので
的外れなことを言っていたらすみません.
初め僕がこのプロジェクトについて聞いた時には
"Pythonのライブラリの使い易さと統一性をCLに実現しよう"
という事だけが目的だったと認識していました.
もしそうであれば,PythonのAPIの実現方法などは
参考までに留めておき,Pythonと同じだけの手間で
CLを使って同じ事ができるようなライブラリを,
CLらしい方法で実現するのが一番良い筈です.
(もしPythonプログラマーがCLで困らない様にするので
あれば
これでは不十分ですし,そもそもCLAPの名前に反するかも
しれませんが)
Lispであれば,統一的なAPIの設計等は
全体像が見えて来てからでも遅くない筈です.
Shiroさんの言う通り,必要な物を適当に書いていく
事から始めても良いと思います.
木脇太一
On Dec 9, 2010, at 6:32 AM, Shiro Kawai wrote:
> パラダイムが違うと難しいですねえ。
> まあ、今の段階では、とりあえず必要になるとわかってる範囲だ
shiroさんもgaraemonさんも頭が良くて良いなぁと思いながら
ぼんやりしてました。
今のイメージのwrapperをdefgenericにひっかけて
defmethodのwrapperも作れば結構ヒネったこともできそうな気がしてます。
lispとpythonで型の階層が受け入れ難いほどに異なる場合は考えますが。
#個人的には現状イメージのextract-argument-symbolsの方が気になる感じして…&restとかは?
というわけで、問題が起きた時に書きなおすに一票。
2010/12/9 Ryohei Ueda <gara...@gmail.com>:
--
佐野匡俊(SANO Masatoshi)
snm...@gmail.com
皆さん, 返信ありがとうございます
そうですね, pythonのfull implementationとかに話が逸れて行ってしまうのが一番怖いです
というわけで,
(my-class-method 'integer arg0 arg1)
みたいに呼び出せる, というAPIで実装していきたいと思います.
裏で走る実装は適時書き換えるという感じで
> #個人的には現状イメージのextract-argument-symbolsの方が気になる感じして…&restとかは?
な, 何も考えていなかった...
&wholeとかを使えば良いんですかね?
-- ryohei
2010/12/9 SANO Masatoshi <snm...@gmail.com>:
これはsimple-stringとかの抜けがあるきがしているんですが...
http://www.lispworks.com/documentation/HyperSpec/Body/04_cg.htm#classtypecorrespondence
これで正しいのかな? conditionはbuilt-in-classではない?
https://gist.github.com/735708
SBCLでしかためしていないので, 他の処理系でも試してもらえるとうれしいです
-- ryohei
(pprint (mapcar #'class-name (remove-if-not #'(lambda (x) (eq
(find-package :common-lisp) (symbol-package (class-name x))))
(ENUMERATE-ALL-CLASSES))))
(FUNCTION FILE-STREAM STRING-STREAM STREAM TYPE-ERROR PROGRAM-ERROR
PARSE-ERROR CONTROL-ERROR END-OF-FILE READER-ERROR STREAM-ERROR
FILE-ERROR PACKAGE-ERROR UNBOUND-VARIABLE UNDEFINED-FUNCTION UNBOUND-SLOT
CELL-ERROR DIVISION-BY-ZERO FLOATING-POINT-OVERFLOW
FLOATING-POINT-UNDERFLOW FLOATING-POINT-INEXACT
FLOATING-POINT-INVALID-OPERATION ARITHMETIC-ERROR PRINT-NOT-READABLE
ERROR STORAGE-CONDITION SERIOUS-CONDITION STYLE-WARNING WARNING
SIMPLE-WARNING SIMPLE-ERROR SIMPLE-TYPE-ERROR SIMPLE-CONDITION CONDITION
PACKAGE BROADCAST-STREAM SYNONYM-STREAM ECHO-STREAM TWO-WAY-STREAM
CONCATENATED-STREAM RESTART RANDOM-STATE HASH-TABLE READTABLE
LOGICAL-PATHNAME PATHNAME STRUCTURE-OBJECT METHOD METHOD-COMBINATION
STANDARD-METHOD STANDARD-GENERIC-FUNCTION GENERIC-FUNCTION STANDARD-CLASS
STRUCTURE-CLASS BUILT-IN-CLASS CLASS STANDARD-OBJECT CHARACTER SYMBOL
BIGNUM FIXNUM INTEGER RATIO RATIONAL DOUBLE-FLOAT SINGLE-FLOAT FLOAT REAL
COMPLEX NUMBER SIMPLE-ARRAY ARRAY NULL CONS LIST BASE-STRING
SIMPLE-BASE-STRING SIMPLE-STRING STRING SIMPLE-BIT-VECTOR BIT-VECTOR
SIMPLE-VECTOR VECTOR SEQUENCE T)
-- ryohei
2010/12/10 Ryohei Ueda <gara...@gmail.com>:
こんな感じの図を良く見る気がしていたんですが、
http://farm3.static.flickr.com/2440/3772201180_6222bed6e1_o.png
どこに書いているか自分も探しています
2010/12/10 Ryohei Ueda <gara...@gmail.com>:
2010/12/9 Ryohei Ueda <gara...@gmail.com>:
とりあえず, 実装してコミットしてみました
https://github.com/garaemon/clap/blob/master/src/builtin/meta.lisp
integerのようなインスタンスが直接つくれないbuilt-in-classは,
eqlスペシャライザ(例えばeql 'integer)で何とかすることにしました.
built-in-classのサブクラスは作ってはいけないようなので:
http://www.lispworks.com/documentation/HyperSpec/Body/t_built_.htm
この実装だと:
・call-next-methodの上書き
・built-in-classクラスメソッド呼び出し時の継承ツリーの解決
たとえば, realクラスに対してclassmethod hogeが定義されてるときに,
integerクラスに対してhogeを呼び出すとエラー
という問題がありますが, しばらく目をつぶっても良いかな,
と思ってます
-- ryohei
2010/12/10 Shiro Kawai <shiro...@gmail.com>: