From: keiju@... (Keiju ISHITSUKA) Date: 1998-03-30T15:24:46+09:00 Subject: [ruby-dev:1989] Re: coerce けいじゅ@日本ラショナルソフトウェアです. In [ruby-dev :01924 ] the message: "[ruby-dev:1924] Re: coerce ", on Mar/25 16:47(JST) toyofuku@juice.or.jp writes: > 豊福@パパイヤです。 > > だいぶ間をあけてしまってすみません。 私もだいぶ間を空けてしまいました(^^;;; # 別のものにかかりっきりだったもので. >>>(2) 本当は Numericクラスあたりでやらしたいことを >>> わざわざ Scalarクラスのオブジェクトを作って >>> それにやらしている。 >> 2. Numericで行列に関する演算が定義されていて, クラスを静的に考え過ぎ >> ているというのが気になります. というのも rubyは動的な言語なので後か >> らクラスが追加されていくわけですが, そのたびにNumericにメソッドを定 >> 義するのは気が引けるということです. > > でも今回の Matrix の件でも実質的に Numeric op Matrix >を定義しているのですから Numeric に追加できるのが一番 >自然じゃないでしょうか。 > Numeric op Matrix の定義は自然なもので論理的な悪影響 >はないように思えますが、再定義は避けている理由にはどの >ようなことがあるのでしょうか。 組み込みクラスとして最初っからMatrixがあるなら, そういう実装で全然問題 ないと思います. 後からrequireして組み込みが行なわれるモジュールが複数ある場合を考えま す, この場合 Rational/Complex/Matrix などが考えられますよね. で, これ らのクラスは一応独立でどのような組合せでも使うことができます. >class Numeric > def *(other) > case other > when Matrix > return other.collect{|e| self * e} > ... > end > end >end Numeric::* もこのような実装では不十分で: -- matrix.rb-- class Numeric alias old_mul * def *(other) case other when Matrix return other.collect{|e| self * e} else self.old_mul(other) # 旧定義で実現されている演算を呼び出す. end end end とこんな感じで, 以前の定義を呼ぶようにしてあげなくてはなりません. この 時問題になるのが, aliasするメソッド名管理です. -- complex.rb-- class Numeric alias old_mul * def *(other) case other when Complex return other.collect{|e| self * e} else self.old_mul(other) end end end となっていると, require "matrix.rb" require "complex.rb" 1 * Complex(1,2) は一見正しく動作しそうですが, 無限ループにはいってしまいます. これは, matrix.rbとcomplex.rbで同じメソッド名でaliasを行なってしまったためです. また, load "complex.rb" load "complex.rb" の様に同じクラスを2度ロードした時も同じことが起こります. # 実をいうと, elispで同じ問題で良く苦労するんですよね(^^;;; だからこの # 方法は好きじゃないんですけどね. こんな感じで, この方法ですと, 1. alias名の管理が面倒 2. へんなaliasがNumericの下にいっぱいできてしまう. ということで, 私はあまり推薦できません. あと, モジュール管理の面からいうと, 面倒なことは基本的なクラスではなく複雑なクラスで行なう. という原理からいってもMatriz側で行なった方が良いんでは? って気がします. Numeric op MatrixをNumeric側で定義することは, NumericがMatirxの性質を 知っていることになります. このことは, 本来持つ必要のない性質をNumeric に持たしていることになります. >> # ついでに言えば, Numeric::* の様な指定はできません. > > 要は Numeric で定義した乗算が呼び出されるようにした >かっただけですので、もしやるんだったら "*" の再定義に >ならないように別の名前にするべきだったんでしょうか。 > 例えば > class Matrix > def coerce(other, meth) > ... > case other > when Numeric > return other, self, numeric_mult > ... > end > end > > class Numeric > def numeric_mult(other) > ... > end > end これだと, aliasの問題はだいぶなくなりますが, こうするんだったら, case other when Numeric return self, other, mult_r ... のでも同じですし, 名前管理の問題は全くなくなりますし, 先ほどのモジュー ル管理の面からも良いと思いますよ. # ただ, どちらでも実装できることは確かなので, 実際に実装する人に任され # ることになると思いますけどね. >>>まさか exp(M) を計算して返そうと・・・ >> 多分その通りです. jordan標準形が求まればexp(M)は求まりますし... > > 半分冗談のつもりで書いたのですが本当にそのつもり >だったとは・・・。 # そういうことは結構好きなんです(^^;;; >> ただ, その前提になる固有値を求める部分で挫折してしまってあきらめてしま >> いました(^^;;; > > jordan標準形を求めるメソッドあるといいですね。当然 >ながら高次方程式の根を求めてくれるメソッドもあると >いいなあ。 ほしいですねえ... でも, rubyでやるのは重いかなって気もするし... >> # 話しは違いますが, complex ** complex, sin(complex)とかは頑張って(適 >> # 当に)定義しているんですよねえ... ただ, 正しいかどうか分からんので誰 >> # か検算(?) して欲しいんですが... > complex ** complex は正しいような気がします。 >sin と cos は両方とも虚数部の符号が逆のような気がするの >ですがどうやって確認したものか。 うぅ... 誰か頭の良い数式処理システムor数値処理システムで検算してくれないかなあ... __ ................................石塚 圭樹@日本ラショナルソフトェア... ----------------------------------->> e-mail: keiju@rational.com <<---