ごとけんです

In message "[ruby-dev:4927] Re: module Precision"
    on 99/02/09, 石塚圭樹 <keiju / rational.com> 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