From: gotoken@... (GOTO Kentaro) Date: 1999-02-10T06:07:23+09:00 Subject: [ruby-dev:4953] coerce the next generation ごとけんです In message "[ruby-dev:4927] Re: module Precision" on 99/02/09, 石塚圭樹 writes: >けいじゅ@日本ラショナルソフトウェアです. >>ごとけんです > >>なんか僕が先走ってるような気もするので些細な疑問でも >>おっしゃってください. > >(^^;;; しかも意志の疎通がヘタですみません m(_ _)m >> prec の引数にもってこれるのは kind_of?(Precision) に限ろう >> >>というのが中心的な指針です.そのためには [ruby-dev:4850] >>でも述べたように,精度を実現するクラスのみが Precision を >>インクルードするのが混乱のない方法だと認識しています. > >えーと. 別メイルで指摘してある通り, そうじゃない例外もありマスです. 長くて恐縮なんですが,次のような感じで使うと いいと思ってました.が,確かに下の coerce で出て来る super は Precision#super ではないので良くないですね. 名残惜しいですが,やっぱり Precision#coerce は追加しません. require "rational" class Rational include Precision def prec(klass) if klass <= Integer to_i elsif klass <= Float to_f elsif klass <= Rational Rational(self) else klass.induced_from(self) end end def Rational.induced_from(x) case x when Integer Rational.new!(x) when Float xpnt = 15 a,b = format("%.#{xpnt}e", x).split("e") a = a.delete(".").to_i b = b.to_i - xpnt if b < 0 b = -b else a * 10**b b = 0 end Rational(a, 10**b) when Rational Rational(x) else raise "undefined conversion from #{x.type} `#{x}' into Rational" end end def coerce(other) if other.kind_of?(Float) [self.prec(Float), other] else super end end end # ちなみに 上の Rational.induced_from(float) は趣味なので # 無視されても構いませんが,Float には基数2で仮数と # 指数の値を返すメソッドがあってもがいいとは思っています. >coerceには実質的にprecに似たことをやっている部分がかなりあるので, どう >にかしたいと思いちょっと考えてみました. で: (中略) >いまのcoerceとSmalltalkのgeneralityを足して2で割ったものを導入する案で >す. どういうメソッドかというと > > Num1.coerce_type(Num2) -> precすべきクラスの配列を返す > >例: > > Fixnum.coerce_type(Bignum) -> [Bignum, Bignum] > (Fixnum/Bignum).coerce_type(Float) -> [Float, Float] > (Fixnum/Bignum).coerce_type(Rational) -> [Rational, Rational] > Float.coerce_type(Rational) -> [Float, Float] > (Fixnum/Float/Rational).coerce_type(Complex) -> [Complex, Complex] > (Fixnum/Float/Rational/Complex).coerce_type(Matrix) > -> [Matrix::Scalar, Matrix] > ># 最初は, 配列を返さなくて1つの値だけで良さそうでしたがMatrixがうまく ># いきませんでした. > >いまのcoerceアーキテクチャはcoerceで適当に変換して再演算しているわけで >すね. さらに, 一段噛ませるイメージです. > >def op(other) >1. 演算できる時は計算する >2. 演算できない時は, other.coerce_type(self)で変換すべきクラス(N, M)を得る >3. self.prec(N) op other.prec(M) >end > >どうせ変えるんだったら, 昔の豊福さんの案もマージして > > [N', M', op'] = M.coerce_type(N, op) > >も良いかも. 同意します. 同時に行き違いの原因がなんとなく分かったような気が. 僕は上の self.prec(N) op other.prec(M) という表現が 嫌いです.僕が prec に対して偏執すぎるのかも知れませんが, prec はあくまで精度を決めて欲しいと思います. だから,うえの self.prec(N) は N.induced_from(self) なら 名前的に構わないけどメソッド形式でないのは確かに不便です. そこで,各クラスは project という各要素を置き換えた結果を 返すブロックメソッドを用意し,この project を使って次を 行うメソッド over をモジュールで提供するのはどうでしょう. def be_over(klass) project{|i| klass.induced_from(i)} end これで,self.be_over(N) なら全然気になりません. ちなみに project のようなモノがあると collect! に相当する ものも作れるので,だいぶ前から何故ないんだと思ってました. >あと, 上記opの定義2,3は全て共通なので > >def op(other) > 計算できる時は計算してretuen > super >end > >と書けるようになっていると完璧ですね. > >皆さん. いかがでしょう? このようなことができるのは理想的ですね. # いったい誰が実装するのでしょう(^^;; ただ,この問題は Precision とは分けて考えたいというのが 僕の気持ちで,Algebra というモジュールにした方がよいような 気がしています. あんまりモジュールを増やしてはいけないのかも知れませんが. -- gotoken