From: matz@... (Yukihiro Matsumoto) Date: 1998-11-20T13:50:58+09:00 Subject: [ruby-dev:3601] Re: Multiple assignment at yield() まつもと ゆきひろです In message "[ruby-dev:3600] Re: Multiple assignment at yield()" on 98/11/20, Shin-ichro Hara writes: |原です。 ||親知らず抜いて来ました.痛かったです.(;_;) | |不幸ですねえ。今時は無痛でできるのかと思ってけど、、、ヤブだった |のかも。:-) ヤブかどうかはにわかには判断できませんが,私の親知らずの状態 が尋常ではなかったので(顎の骨の中にやや下向きに(!)生えてい た),痛いのはしょうがなかったように感じています. 今は片方宍戸錠状態です. || def each7; @body.each { |x| yield(*x) } end || Foo.new([7]).each7 { |x| p x } #=> [7] | |これは #=> 7 の typo ですよね。 違います.[7]です. |そうだとするとこれら 18 個の結果は現在の 1.1c のものと全く |一致しています。後退してしまった? 後退したといえないことはないと思いますが,多重代入とyieldに おける* の動作を再検討してちゃんと実装したらこうなったって感 じです.あ,でも,今考え直したらやはり不備があるようですね. もうちょっと再検討しなくては. |私の、一番最初の提案は | || def each7; @body.each { |x| yield(*x) } end || Foo.new([[7]]).each7 { |x| p x } #=> [7] | |これを #=> 7 にしたらどうか、というものでした。 このeach7の動作は x に yield された値(この場合は[7])を受け取り, それを yield *[7] する ということですから 7 の方が良いですね.そうか. それを加味すると結果は Foo.new([0]).each0 { |x| p x } #=> 0 Foo.new([1]).each1 { |x| p x } #=> 1 Foo.new([2]).each2 { |x| p x } #=> [2] Foo.new([3]).each3 { |x| p x } #=> 3 Foo.new([4]).each4 { |x| p x } #=> 4 Foo.new([5]).each5 { |x| p x } #=> 5 Foo.new([6]).each6 { |x| p x } #=> [6] Foo.new([7]).each7 { |x| p x } #=> 7 Foo.new([8]).each8 { |x| p x } #=> 8 Foo.new([[0]]).each0 { |x| p x } #=> [0] Foo.new([[1]]).each1 { |x| p x } #=> 1 Foo.new([[2]]).each2 { |x| p x } #=> [2] Foo.new([[3]]).each3 { |x| p x } #=> 3 Foo.new([[4]]).each4 { |x| p x } #=> [4] Foo.new([[5]]).each5 { |x| p x } #=> 5 Foo.new([[6]]).each6 { |x| p x } #=> [6] Foo.new([[7]]).each7 { |x| p x } #=> 7 Foo.new([[8]]).each8 { |x| p x } #=> [8] になりますね. |そして次の提案は | || def each6; @body.each { |*x| yield(x) } end || Foo.new([[6]]).each6 { |x| p x } #=> [6] | |これを #=> [[6]] にしたらどうかということです。つまり、 | | 1) yield(*x) は無条件に x の一番外側の [] を剥ぎとって | 代入の右辺に置く | 2) *x = は無条件に右辺に [] を付けて受ける | 3) それ以外はいままで通り | |というものです。したがって、、、 こっちはいまいち受け入れがたく感じています.というのも (1) yieldの元々の挙動が「1要素はそのまま,2要素以降は配列 化して渡す」というものですから.が,each7で分かったよ うに,*がつけばプログラムの字面上その配列の(配列でなけ れば配列化した)内容が展開された時と同じ動作をするよう にしようと思います. (2) *xというのは「右辺の残りを代入する」という意味です.多 重代入ですから,右辺は配列化されます.ですから,右辺に コンマが無く,その値が配列でないものが来た時には [] を つけて受けることになります(現状の動作). これを「無条件に [] をつける」となると,「右辺が配列で ない時には配列化する」という多重代入の原則が崩れるよう に思えるのですが,違うのでしょうか? と,思っていたのですが, |だけです。さて、右辺に 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, *b = 1, [3]; # a=1, b=[[3]] なのに *b = [3]; # b=[3] なのはおかしいということですね.それは確かに. |話を 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 | .... | |ここまではいいでしょうか?合ってますか? おおむね合ってます.些細な補足は Y がコンマで区切られた式だっ た場合,無条件に[Y]と解釈されることです. まつもと ゆきひろ /:|)