From: Shin-ichro Hara Date: 1998-11-20T12:47:15+09:00 Subject: [ruby-dev:3600] Re: Multiple assignment at yield() 原です。 In message "[ruby-dev:3598] Re: Multiple assignment at yield()" on 98/11/19, Yukihiro Matsumoto writes: | |まつもと ゆきひろです | |親知らず抜いて来ました.痛かったです.(;_;) 不幸ですねえ。今時は無痛でできるのかと思ってけど、、、ヤブだった のかも。:-) ところで、 | def each7; @body.each { |x| yield(*x) } end | Foo.new([7]).each7 { |x| p x } #=> [7] これは #=> 7 の typo ですよね。 そうだとするとこれら 18 個の結果は現在の 1.1c のものと全く 一致しています。後退してしまった? 私の、一番最初の提案は | def each7; @body.each { |x| yield(*x) } end | Foo.new([[7]]).each7 { |x| p x } #=> [7] これを #=> 7 にしたらどうか、というものでした。 そして次の提案は | def each6; @body.each { |*x| yield(x) } end | Foo.new([[6]]).each6 { |x| p x } #=> [6] これを #=> [[6]] にしたらどうかということです。つまり、 1) yield(*x) は無条件に x の一番外側の [] を剥ぎとって 代入の右辺に置く 2) *x = は無条件に右辺に [] を付けて受ける 3) それ以外はいままで通り というものです。したがって、、、 || (1L) 右辺が配列ならリスト化,そうでなければそのまま || || (2L) 先頭に * が付いた変数には代入しなかった残りが配列とし || て代入される | |とすると(1L)により,右辺がリストでなく,結果が配列でない時に |は,そのまま左辺に代入されるんですね.その場合,以下の代入は |どうふるまうべきですか? | | a, b = 5 | a, *b = 5 | *a = 5 | |つまり,配列でないものを多重代入する時の振る舞いという意味で |すが. 最後の以外はいままで通りであればいいと思います。足らない スカラー b は b = nil、足らないベクトル *b は b = [] が充 填される、と。最後のは a = [5] です。今まで通り。 #なんか話が戻ってしまったなあ。 |私自身の解釈としては(既に述べましたが), | | * 多重代入の右辺は配列化される | | * 先頭に * が付いた変数には代入しなかった残りが配列として | 代入される | |と思っています.つまり,*a = x と a = x の違いは右辺が配列化 |されるかどうかにあると思っているわけです. ううむ、分かっているつもりなんですがね。記号で書いてみますね。 配列化を A() で表すと、 A(1) = [1] A(1, 2) = [1, 2] A([1]) = [1] A([1, 2]) = [1, 2] A(1, *[2]) = [1, 2] A(1, *[2, 3]) = [1, 2, 3] A(1, *2) = [1, 2] A(*[1]) = [1] A(*[1, 2]) = [1, 2] となります。次に B() を強制的な配列化とします。A との違いは B([1]) = [[1]] B([1, 2]) = [[1, 2]] だけです。さて、右辺に Array しか許さない(多重)代入を <= と 書きますね。 a, b, *c <= [1, 2, [3]] #=> a = 1, b = 2, c = [[3]] a, *b <= [1, 2, [3]] #=> a = 1, b = [2, [3]] *a <= [1, 2, [3]] #=> a = [1, 2, [3]] これはつまり、 a, b, *c <= [1, 2, [3]] #=> a = 1, b = 2, c = B([3]) a, *b <= [1, 2, [3]] #=> a = 1, b = B(2, [3]) *a <= [1, 2, [3]] #=> a = B(1, 2, [3]) と B を使っていることになります。 そして現状の多重代入を <== と書くと、 多重代入「<== ...」とは「<= A(...)」のことである。 といえるわけですね。合ってますか? 話を yield の方に移して、現在の yield(Y) のパラメータの渡し方は こうですよね。 |x| #=> x = nil [ Y が0要素のとき ] = Y [ x = Y が単純代入の形をしているとき ] = A(Y) [ それ以外 ] 多重代入の左辺の形である X についての |X| は、単に X <== Y を実 行します。 |*x| #=> *x <== X |x, y | #=> x, y <== X |x, *y| #=> x, *y <== X .... ここまではいいでしょうか?合ってますか? |ただ,原さんの定義による挙動の方がよりよいことが示されれば, |変更するのは可能だと思います.鍵は *a という左辺を持つ多重代 |入の解釈かな? 私の提案のスキームについては、昼食を食べてから書きます。(^^;