ブロック変数のスコープは「Rubyの落とし穴」だったのか!
追記 2008/12/16 18:18:41:
1.9では挙動が違う。こういう大事なところは…
>> x=[1,2,3] => [1, 2, 3] >> x.map{|x|x} => [1, 2, 3] >> x => [1, 2, 3] >> proc{|x| x=1}.call(x) => 1 >> p x [1, 2, 3]
ここまで
ライブドアブログ(livedoor Blog)| 読みたいブログが見つかるを読んで衝撃を受けた
まさか仕様だったとは…
#
ブロックの引数のスコープ
a = [1,2,3]
a.sort{|a,b| b<=>a} # a に代入される
p a.class #=> Fixnum # 最後に代入された a
なんてことだ。
>> x=[1,2,3] => [1, 2, 3] >> x.map{|i|i} => [1, 2, 3] >> x => [1, 2, 3] >> x.map{|x|x} => [1, 2, 3] >> x => 3
一方、ブロック内ので更にブロックを使った場合には汚染されない。
>> x=[[1,2],[3,4,5],[3]] => [[1, 2], [3, 4, 5], [3]] >> x.map{|i|i.map{|i|i}} => [[1, 2], [3, 4, 5], [3]] >> x.map{|i|i.map{|i|i+1}} => [[2, 3], [4, 5, 6], [4]] >> x.map{|i|p i;i.map{|i|p i;i+1}} [1, 2] 1 2 [3, 4, 5] 3 4 5 [3] 3 => [[2, 3], [4, 5, 6], [4]]
どういうことだ?
いいの?これで?
schemeで言えば
>>(define x '(1 2 3)) =>x >>(map (lambda (x) x) x) =>(1 2 3) >>x =>(1 2 3)
こういう事だろ?おかしいよ。rubyのブロックって一体何だ?
んん?
>> proc{a=2}.call => 2 >> a=proc{|i| p i} => #<Proc:0xb7f6eb30@(irb):6> >> a.call(1) 1
こうやってかんがえると common lispとおなじなら
(let ((x '(1 2 3))) (funcall (lambda (x) x) x) (print x)) (1 2 3)
だから、procで書くと
>> x=[1,2,3] => [1, 2, 3] >> proc{|x| x=1}.call(x) => 1 >> p x 1
こういう事かぁ lambda (x) のxが汚染されるんだな。
ちょっとまてよ commonlispならどうなるんだ?
(let ((x '(1 2 3))) (funcall (lambda (i) (print x)) x) (print x)) (1 2 3) (1 2 3)
lambdaの外はのぞけているなぁ。ブロック引数の汚染に何の意味があるんだろう?