From: Akinori MUSHA Date: 2009-02-26T17:18:15+09:00 Subject: [ruby-dev:38095] Re: [Feature:trunk] nested loop construct --pgp-sign-Multipart_Thu_Feb_26_17:19:48_2009-1 Content-Type: text/plain; charset=ISO-2022-JP At Thu, 26 Feb 2009 14:52:05 +0900, Yugui wrote: > On 2/26/09 3:33 AM, Yukihiro Matsumoto wrote: > > 検討事項は > > * 名前。今回はnested loopということでnloopという名前で実装 > > したが、もっと適切な名前があるかもしれない。妙な短縮形よ > > りも長くても記述的な名前を好む人も多いかも。Ruby(というか > > 私)は前者を好む傾向はあるけど > > Array#productがカルテシアン積なので、それに合わせてEnumerator#productで > > nphi.product(ntheta).each {} や  インスタンスメソッド形式は、(Array#zip 等でも感じることですが) 3つ以上あるときに、本来対等な関係にも関わらず v1.product(v2, v3) とか v, *vs = *vectors v.product(*vs) と「主」を立てないといけないのがどうも気に入らないんですよね。  その点、こちらは記法としては美しいと思います: > (nphi * ntheta).each {} しかし、 Enumerable の演算子とするのは現実的に不可能(Array#* 等と 衝突する)なので、結局は各オペランドを to_enum (each) してから演算 せざるを得ず、演算するため(だけ)にわざわざ変換するというのはやや 使い勝手に欠ける印象があります。  Enumerator のクラスメソッドで実装するのはどうでしょうか。 class << Enumerator def product(*enums) return to_enum(__method__, *enums) unless block_given? return nil if enums.empty? e, *es = *enums if es.empty? e.each { |x| yield [x] } else e.each { |x| product(*es) { |xs| yield [x, *xs] } } end nil end alias nest product end Enumerator.nest(1..3, 'a'..'c', [true, false]) { |x| p x }  もし簡潔さにこだわるなら、 {Class,Module}#* は今後ないだろうと 見切って alias * product してしまえば Enumerator.*(1..3, 'a'..'c', [true, false]) { |x| p x } と書けますね…。  ただ、演算子を導入し始めると、類推や一貫性への期待から次々と 新しい提案がなされ、利便性と理論的整合性の間で苦しみ続けることに なるのではないかという懸念も持っています。 (cf. Feature #709 [ruby-core:19681])  なお、他に思いついたクラスメソッドは Enumerator.transpose (synchronize) Enumerator.join (<< or +) などです。(前者は generator ライブラリの SyncEnumerator と同等) -- Akinori MUSHA / http://akinori.org/ --pgp-sign-Multipart_Thu_Feb_26_17:19:48_2009-1 Content-Type: application/pgp-signature Content-Transfer-Encoding: 7bit -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (FreeBSD) iEYEABECAAYFAkmmUKQACgkQkgvvx5/Z4e5ZRQCghchxhzw7Iw/JKmqb5zdr4ri0 0rQAn2hR10BG1EE17KXtYtTdE8tMGzyc =EFoZ -----END PGP SIGNATURE----- --pgp-sign-Multipart_Thu_Feb_26_17:19:48_2009-1--