2013-05-22 11 views
9

初心者Rubyの質問。このコードを変更する最も簡単な方法は何ですか?ブロックを完全にそのまま残して、副作用を解消するruby​​ proc/lambdaで本当にローカル変数を使う方法

$ irb 
irb(main):001:0> x = lambda {|v| x=2 
irb(main):002:1> v} 
=> #<Proc:[email protected](irb):1> 
irb(main):003:0> x.call(3) 
=> 3 
irb(main):004:0> x 
=> 2 

これは私の問題を説明するための工夫ができ、最も簡単な例であるので、「割り当てを削除」または「XへのPROCを割り当てないと、」私が探しているものではありません。

元の囲みスコープに影響を与えずに割り当てることができるProc(またはラムダ)にローカル変数を設定したいとします。ブロックをラップするクラスやモジュールを動的に作成することはできますが、それはそのような基本的なことのために残酷に思えます。

私がやろうとしているものに

同等のPython:

def x(v): 
    x = 2 # this is a local variable, what a concept 
    return v 
+0

外部変数と同じ名前を使用してみませんでしたか? –

+0

'x'は外部スコープで宣言されている場合はクロージャ変数です。 '_x'のように、これらの変数の名前を変更できないような条件がありますか?あなたはRuby言語の基本的な期待を無効にしようとしています。 – tadman

+0

明らかに、メソッド内にローカル変数を持つことは可能です。 VMに新しいレキシカルスコープを作成する唯一の言語構造ですか?もしそうなら、 'Proc'と' lambda'は適切な関数型プログラミングを行うのに使うことができないという点で安いようです。 – wberry

答えて

25

時にはそれが望ましい動作です:

total = 0 
(1..10).each{|x| total += x} 
puts total 

しかし、時にはそれは偶然のだとあなたは同じ名前を持つようにたまたま外に変数を台無しにしたくありません。その場合は、セミコロンとブロックローカル変数のリストをパラメータのリストに従います。

x = lambda{|v; x| x = 2; v} 
p x.call(3) #3 
p x #<Proc:[email protected]:2 (lambda)> 
+2

引数リストにローカル変数を定義する際の呼び出しが良い!これは、OPが拘束から解放する必要がなくても、OPが望むものを正確に達成するはずです。 –

+4

聖なるくそ。私は毎日何か新しいことを学びます。引数リストのローカル変数をこのようなセミコロンで「宣言」することができるかどうかわかりませんでした.O – nzifnab

+0

構文エラーが表示されるのはなぜですか? http://pastebin.no/z3415 – Dog

6

この理由は、ラムダは、その定義スコープ(NOTその呼び出し範囲)に結合され、全閉であり、されていることですは、とりわけローカル変数xを含みます。あなたは本当にがほしいと思っています。これは、Rubyが設計上非常に簡単に行うことではありません(evalで可能ですが、それはブロックのほうが少なく、文字列の文だけです)。 Procs、lambdas、およびblocksはすべて、定義されたスコープにバインドされています。レキシカルスコープは、クラス、モジュール、およびメソッドでのみ確立されます。ブロック/ procs/lambdas /その他のものではありません。

Pythonでは最初にlambdaの割り当てを許可していないことに注意してください。

+0

評価の可能性は興味深いです。しかし、それは評価をしたものの範囲に変数をバインドするだけでしょうか?私はそれが基本的にパフォーマンスのペナルティになると思う。 – wberry

+0

ええ、Pythonの 'lambda'は残念なことに、割り当て*(whileループや他の*文*)が実行されないようにする単一の*式*を変更するという事実によって弱められています。それは構文上の理由です。 – wberry

+0

正しい。 Rubyで実行されるすべてのものは、そのスコープが空の場合でもスコープを含む* some *にバインドされています。 –

関連する問題