これつぐです。


複数のメールを引用しているのでスレッドは切ってしまいました。
ごめんなさい。

長いので最初に主張をまとめておきます。

  * 実は組み込みには消極的
  * 名前をつけるなら rand       ← rand は「要素をランダムに選ぶ」
  * 定義する対象は Enumerable   ← rand は Enumerable と不可分?
  * Enumerable == Set == Collection ?


[ruby-dev:8482] Re: [REQ] {enumerable, integer, range}.rand
>   かんだです。

> > each で出来ないのはそのとおりなんですが、
> > 結果的に Enumerable なクラスでは同じ程度には有用なので、
> > どうせ Range や Array で定義するんだったら、
> > Enumerable でやってしまったほうがいいという考え方もできませんか?
> 
>   Enumerable は実装上簡単ですが、気持ち悪いです。親クラスを is_a でなく
> 実装の共用に利用しちゃうっていうよろしくない手法じゃないでしょうか?

Module/Mix-in はまさに「実装を共有するため」にあるので、
そのこと自体に問題はないと理解しています。
問題になるのはそれが「適切かどうか」ですが、
適切だと思っているのは今のところ私だけのようで……。

>   僕としては Collection モジュールを作る、というのが嬉しいぞ。
> # Collection って前に話出ましたっけ?

ほかでも名前があがっていますが正確にはどんなものなのでしょう?
最初に書いたとおり私は Enumerable/Set/Collection の区別ができていません。
以下、Enumerable と書いてあっても、
Set あるいは Collection にすべきところがありましたら、
適宜読み替えてください。
指摘していただければさらに嬉しいです。

[ruby-dev:8487] Re: [REQ] {enumerable, integer, range}.rand
> まつもと ゆきひろです

> 現状のrand(max)は「maxまでの範囲内の乱数を発生する」という以
> 上の意味を持ってません。引数や戻り値の意味を変更するならば、
> それはそれで良いのですが、それならば統一的な意味が必要だと思
> います。

統一的な意味づけとして「ランダムに(一つ)選ぶ」を提案します。

rand(10) が rand(0..10) でも rand(1..10) でも
rand((0.0)..(10.0)) でもなく、rand(0..9) なのはなぜでしょう?
(引数「未満」の「整数」を返すのはなぜか?)
推測ですが、これは配列等が意識されていると思います。
つまりすでに要素という概念と結びついているのではないでしょうか。
だとすると、
rand(n) を「0 から n-1 の範囲の乱数を発生する」と読むより、
「n 個の中からランダムに一つ選ぶ」と読むほうが自然です。(強引?)
で、返り値が数値なのは大人の事情(?)であって、
Ruby のような高級言語では必ずしも数値である必要はない、と。

また、仮に rand(Range) あるいは Range#rand を許すとすると、
Range よりもう少し広いクラスで定義できそうです。
なぜなら Range には順序がありますが、
rand にとっては順序は意味がないからです。
つまり rand([0, 1, 2, 3]) も rand([2, 0, 3, 1]) も意味は同じです。
で、「もう少し広いクラス」として私は Enumerable をあげているわけです。

数値以外に拡張する根拠としては dup をあげます。
すなわち、dup を「『file descriptor を』複製する」とは読まずに
「file descriptor を『複製する』」と読んだように、
rand を「『数をランダムに』一つ選ぶ」とは読まずに
「数を『ランダムに一つ選ぶ』」と読めないでしょうか。


[ruby-dev:8488] Re: [REQ] {enumerable, integer, range}.rand
> まつもと ゆきひろです

> んなことはないですよ。Enumerableってのは「順に要素が取り出せ
> る」という意味しか無いんですから。

Enumerable はもっと厳しい制限だと思います。
本来は "Iteratable" とでも言うべきものだったのかもしれませんが、
実情は Set (より正確には finite set?)であると思います。

可算集合(countable set)、たとえば「素数の集合」オブジェクトは
要素を順に取り出せるという意味では Enumerable です。
(prime_number.each{|n| ... } とできますよね?)
が、 Enumerable の半分ぐらいのメソッドは意味がありません。
(each_with_index{}, find{}, grep(){}, member?{}, index() 以外はだめ?)

こういった理由もあって、私は Enumerable と FiniteSet を同一視していますが、
これは間違いで、独立な概念なのでしょうか。

>   class Random
>     include Enumerable
>     def initialize(max)
>       @max = max
>     end
>     def each
>       loop do
>         rand(@max)
>       end
>     end
>   end
> 
> とかね。

むむむむむ……。
申し訳ありませんがよく理解できません。
これは「順に要素が取り出せるという意味しかない」
例になっているということですか?

> また、Enumerableでrandを実現するためには、一度全部の要素を配
> 列に変換する必要があり、効率の悪さ、繰り返しできない可能性な
> どの要素を考えても賛成できません。

正直言って実現方法等について判断できる能力がないのですが、
と前置きしたうえで。
ここで言う配列とは Array オブジェクトのことですか?
それなら効率が悪そうですが、そこまでする必要はないような気がします。
C レベルの配列でも効率が悪いのでしょうか。
それに効率が悪いならむしろ組み込みにしてほしいような……。
――そういう話ではないのかもしれませんが。
「繰り返し出来ない可能性」についてもよく理解できません。
# このあたりの話がクリティカルに効いてくるなら
# 私はこの議論には参加する資格を持ちませんので、
# 以降は見守るだけにします……。

> たとえば、
> 
>   f = open("/usr/dict/words")
>   f.rand
>   f.rand
> 
> としたらどうなると思いますか?
> 
>   words = open("/usr/dict/words").readlines
>   words.rand
>   words.rand
> 
> の方が良くないですか? (randという名前は別として)

まつもとさんの期待に反して、あまりちがいを感じません。
むしろ間に手順をはさまないぶん、前者のほうがいいと思うかもしれません。
f.max と同じかそれ以上には自然だと思うのです。

> 前述のようにrandはrand(3)を強く連想させるので、「enumerable
> の要素一つをランダムに得る」という挙動は、名前として不適切で
> しょうし、さらにEnumerable一般に「要素一つをランダムに得る」
> という行為にも賛成できません。

順序のない Enumerable に対する each は
見かけ上ランダムに要素を取ってきているとも言えると思いますが、
これは特殊過ぎる見方でしょうか。