2010年3月14日16:36 Yukihiro Matsumoto <matz / ruby-lang.org>:
>
> 確かにzipはちょっと揺らいだことがあって、ruby-coreで議論した
> ことがあります。結局、その時はレシーバーの長さ優先という結論
> を出したのですが、今思えばあまり良くなかったなあと。たとえば、
> with_indexのようなものをzipを使って作る場合、連番が先頭に来
> れないというのはかなり大きな制約のような気がします。

えぇと、たとえば 0から無限に連番を作る iota と
有限の配列 ary があったとして、
ary.each.with_index {|e,i| } は
ary.zip(iota) {|e,i| } と実現できるが、
iota.zip(ary) {|i,e| } は無限ループになってしまう、という意味ですか?

% ./ruby -e '
iota = Enumerator.new {|y| i = 0; loop { y << i; i += 1 } }
ary = %w[a b c]
ary.zip(iota) {|x,y| p [x,y] }
iota.zip(ary) {|x,y| p [x,y] }
'
["a", 0]
["b", 1]
["c", 2]
[0, "a"]
[1, "b"]
[2, "c"]
[3, nil]
[4, nil]
[5, nil]
...

でも、かなり大きな制約、というのはよくわかりません。

どうせブロック引数で受けとるなら、順番はどうにでもなるのでは?
連番を先頭に表示したければ、
ary.zip(iota) {|e,i| p [i,e] }
とすれば可能ですよね。

議論をしたという [ruby-core:14738] からのスレッドを読むと、
レシーバの長さを優先するとユーザが繰り返しの終了を選べるが、
最短ので止まると選べない、という点が指摘されていて、それには共感を覚えます。

連番は先頭に置いた方がわかりやすい、というならわからないでもないですが、
その利点が、ユーザが選べるという利点を越えるとは感じません。

> 考えたのは、interlave対象に無限列を含む場合です。たとえば
> with_indexをflattenしたようなものを得る時に、停止しないのは
> 使いにくかろうと。

iota.interleave(ary) {|x| p x } が
0, "a", 1, "b", 2, "c", 3, 4, 5, ...
となるのは使いにくい、と。

ふむ。それはそんな気がしないでもないですね。
zip とは違って、ブロック引数でどうにかすることはできませんからね。

でも、停止したとしても、それをどう使うかというのを考えると
結局は使いにくいという結論になるかもしれないとも思います。

> どうも、具体的になりきれないのがいけませんね。

そうですね。具体例があれば、その例について便利かどうかを考えられるんですが、
ここで出てきている例くらいだと、具体性が足りなくてそういうことを考えるのは
難しいです。

Hash[k1,v1,k2,v2,...] は
ks = [k1,k2,...]
vs = [v1,v2,...]
とすると Hash[*ks.interleave(vs)] と書けて、
interleave が有用な例のような気がするんですが、
これ自体は他の方法で解決されているし、
同じような困り方をした他の例は思い出せないんだよなぁ。
-- 
[田中 哲][たなか あきら][Tanaka Akira]