Siena. です。 かなり悩みましたが、自分の中では少し整理できたように思いますので。 ▼ [ruby-dev:17228] < Yukihiro Matsumoto さん [ruby-list:35279] で Ruby は大クラス主義という御指摘もありましたが、 それを踏まえても、やはり Range に連続・離散区間の両方を扱わせるのは 避けたいという見解に (今のところ) 落ち着いています。 とりあえず、そう考える理由を挙げておきたいと思います。 》ちょっと考えてみました。で、結局問題があるのは 》 》 member?, include? 》 step, eachおよびeachを元にしたEnumerableメソッド Enumerable のメソッドは、Enumerable としての挙動をとって欲しいです。 クラス単体で見た場合に Enumerable と異なる挙動であった方が自然であっても、 Enumerable であるとみなして扱う時に Range を特別扱いしないとなりません。 Enumerable その存在が大きいため、例外的なものがあると抽象レベルで 扱う事を難しくしてしまいます。更に Range は組み込みクラスなので、 余計に整合性を損なってしまうのではないかと危惧します。 例えば、Enumerable なオブジェクト群 [ e_1, e_2, ... ] があった時に、 あるオブジェクト val で include? val == true となる e_i において each するといった場合などに、含んでいると判定されたのにもかかわらず each 中に出現しないという状況が発生してします。これを避けるために、 Range のためだけに to_a.include? val とするのも本末転倒と感じます。 連続区間としてのメソッドを Enumerable のメソッドとは異なる 名前で定義する事も、選択肢としてはありえます。しかしこの場合、 Enumerable のメソッド名が汎用的で連続区間としてのメソッドの 名前と競合しやすいため、不自然/冗長な名前になる、似た名前の 異なるメソッドが並存する、などの問題が出てしまうと思います。 これが自然に解決できるようならば一つのクラスにまとめても 良いですが、それは非常に困難ではないかと想像しています。 》 * member?, include? 》 》 Numericであるか、succが定義されていなければ範囲によるチェッ 》 クを行う。succが定義されていれば繰り返してみてその要素が 》 あるかないかをチェック。 というわけですので、Numeric であっても、離散区間 (離散集合) としてのメンバシップ判定を行なって欲しいです。 そうでないならば、Range は Enumerable と似て非なる インターフェイスを持つ事になり、好ましくないと思います。 上の問題と刻み幅を持たせるという事は独立に 考えられるので、こちらは別途考えたいと思います。 ちょっとしつこいようで申し訳ないのですが、 もう少しお付き合いいただけたら幸いです。 以下、便宜上、刻み幅を diff (デフォルトは 1) と表記します。 》 * step, eachおよびeachを元にしたEnumerableメソッド 》 》 eachはsuccが定義されていなければTypeError例外(だから 》 Float のRangeには使えない。これにより全部のEnumerableメ 》 ソッドは要素がsuccを持つ必要がある。 》 》 stepはNumericならstepを毎回+する(Floatでは誤差が蓄積する 》 が、ここでは無視)。それ以外ならsuccを使って定義する。 Range#each で、first と diff の加算が可能であれば diff ずつ進み、 そうでなければ diff (但し、FixNum) 回 succ しつつ進む、という 挙動は、これらの判定ができるならば不自然な定義とは思えませんので、 導入を検討していただきたく思います。これらの判定は、上記の まつもとさん提案のものと同様 (or 改善版) で良いと考えています。 また、Range#each は Range#step( 1 ) 相当とみなされると思います。 つまり、Range#step( n ) は、first と diff の加算が可能であれば diff * n ずつ進み、そうでなければ diff * n 回 succ しつつ進む、 という挙動で定義できると考えています。 改めて次を提案したいと思います。 * 純粋に連続区間を扱うために Interval といったクラスを 導入して、連続・離散区間を扱うクラスを分ける * Range は刻み幅 (デフォルトは従来相当の 1) を持つ範囲として拡張する * Range#interval, Interval#range( diff ) といった メソッドで互いを抽出できるようにする Range#=== を離散区間としてのメンバシップ判定に従わせるか、 従来との互換性を考えて連続区間としてのメンバシップ判定に 従わせるかは、議論のあるところだと思います。 上の提案の場合は、少なくとも、従来の Range#=== は Range#interval.=== (書き方が変 ^^;) 相当とみなせます。 この提案は現実的ではない、もしくは Ruby の方針に合わないでしょうか。 Interval 相当はユーザライブラリとするのでも良いですが、 少なくとも Range は上記のようになっていて欲しいと思います。 # また長くなってしまった... (--; --- Siena. <mailto:siena / cr.chiba-u.ac.jp>