私は最近、Ruby のブロックと生成機能を発見しましたが、疑問に思っていました: これはコンピューター サイエンスの理論のどこに当てはまりますか? それは関数型プログラミングのテクニックですか、それとももっと具体的なものですか?
4 に答える
Ruby のyield
は、C# や Python のような反復子ではありません。yield
Rubyでブロックがどのように機能するかを理解すれば、それ自体は実際には非常に単純な概念です.
はい、Ruby は関数型言語ではありませんが、ブロックは関数型プログラミングの機能です。実際、Ruby はこのメソッドlambda
を使用してブロック オブジェクトを作成します。これは、無名関数を作成する Lisp の構文 (ブロックとは何か) から借用したものです。コンピューター サイエンスの観点からすると、Ruby のブロック (および Lisp のラムダ関数) はクロージャーです。Ruby では、通常、メソッドは 1 つのブロックしか取りません。(もっと渡すこともできますが、厄介です。)
Rubyのyield
キーワードは、メソッドに渡されたブロックを呼び出す方法にすぎません。次の 2 つの例は同等です。
def with_log
output = yield # We're calling our block here with yield
puts "Returned value is #{output}"
end
def with_log(&stuff_to_do) # the & tells Ruby to convert into
# an object without calling lambda
output = stuff_to_do.call # We're explicitly calling the block here
puts "Returned value is #{output}"
end
最初のケースでは、ブロックがあると仮定して、それを呼び出すように言っています。もう 1 つの方法では、Ruby はブロックをオブジェクトでラップし、それを引数として渡します。前者の方が効率的で読みやすいですが、実質的には同じです。次のようにどちらかを呼び出します。
with_log do
a = 5
other_num = gets.to_i
@my_var = a + other_num
end
そして、最終的に に割り当てられた値を出力し@my_var
ます。(OK、それは完全にばかげた機能ですが、あなたはその考えを理解していると思います。)
Ruby では、ブロックは多くのことに使用されます。Java のような言語でループを使用するほとんどすべての場所は、Ruby ではブロックを取るメソッドに置き換えられています。例えば、
[1,2,3].each {|value| print value} # prints "123"
[1,2,3].map {|value| 2**value} # returns [2, 4, 8]
[1,2,3].reject {|value| value % 2 == 0} # returns [1, 3]
アンドリューが指摘したように、ファイルや他の多くの場所を開くためにも一般的に使用されます. 基本的に、何らかのカスタム ロジック (配列の並べ替えやファイルの処理など) を使用できる標準関数がある場合はいつでも、ブロックを使用します。他にも使い道はありますが、この回答が長すぎて体の弱い読者が心臓発作を起こすのではないかと心配しています。うまくいけば、これでこのトピックに関する混乱が解消されます。
単にループするだけではなく、生成してブロックする必要があります。
シリーズEnumeration enumerableには、グループの任意のメンバーに対してステートメントが true かどうか、またはすべてのメンバーに対して true かどうかを尋ねたり、特定の条件を満たす一部またはすべてのメンバーを検索したりするなど、列挙を使用して実行できる一連の操作があります。 .
ブロックは可変スコープにも役立ちます。便利というだけでなく、デザイン性にも貢献します。たとえば、コード
File.open("filename", "w") do |f|
f.puts "text"
end
例外が発生した場合でも、ファイルストリームが終了するとファイルストリームが閉じられ、終了すると変数がスコープ外になることが保証されます。
何気なくグーグルで検索しても、Ruby のブロックと歩留まりに関する適切なブログ記事は思いつきませんでした。どうしてか分かりません。
コメントへの返信:
変数がスコープ外になったからではなく、ブロックが終了したために閉じられたと思います。
私の理解では、オブジェクトを指している最後の変数がスコープ外に出ても、そのオブジェクトがガベージ コレクションの対象となることを除けば、特別なことは何も起こらないということです。ただし、これを確認する方法がわかりません。
ファイル オブジェクトがガベージ コレクションされる前に閉じられることを示すことができますが、これは通常すぐには行われません。次の例では、2 番目のステートメントでファイル オブジェクトが閉じられていることがわかりますが、puts
ガベージ コレクションは行われていません。
g = nil
File.open("/dev/null") do |f|
puts f.inspect # #<File:/dev/null>
puts f.object_id # Some number like 70233884832420
g = f
end
puts g.inspect # #<File:/dev/null (closed)>
puts g.object_id # The exact same number as the one printed out above,
# indicating that g points to the exact same object that f pointed to
このステートメントはCLU言語yield
に由来すると思います。トロンのキャラクターもCLUにちなんで名付けられたのだろうかといつも思う....
「コルーチン」はあなたが探しているキーワードだと思います。
例http://en.wikipedia.org/wiki/Yield
コンピューティングおよび情報科学における歩留まり:
- コンピューター サイエンスでは、コルーチンのリターン (および再エントリ) のポイント