50

私は最近、Ruby のブロックと生成機能を発見しましたが、疑問に思っていました: これはコンピューター サイエンスの理論のどこに当てはまりますか? それは関数型プログラミングのテクニックですか、それとももっと具体的なものですか?

4

4 に答える 4

105

Ruby のyieldは、C# や Python のような反復子ではありません。yieldRubyでブロックがどのように機能するかを理解すれば、それ自体は実際には非常に単純な概念です.

はい、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]

アンドリューが指摘したように、ファイルや他の多くの場所を開くためにも一般的に使用されます. 基本的に、何らかのカスタム ロジック (配列の並べ替えやファイルの処理など) を使用できる標準関数がある場合はいつでも、ブロックを使用します。他にも使い道はありますが、この回答が長すぎて体の弱い読者が心臓発作を起こすのではないかと心配しています。うまくいけば、これでこのトピックに関する混乱が解消されます。

于 2009-04-19T09:28:34.273 に答える
6

単にループするだけではなく、生成してブロックする必要があります。

シリーズ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
于 2009-04-19T04:58:05.437 に答える
2

このステートメントはCLU言語yieldに由来すると思います。トロンのキャラクターもCLUにちなんで名付けられたのだろうかといつも思う....

于 2009-04-18T20:29:37.610 に答える
0

「コルーチン」はあなたが探しているキーワードだと思います。

http://en.wikipedia.org/wiki/Yield

コンピューティングおよび情報科学における歩留まり:

  • コンピューター サイエンスでは、コルーチンのリターン (および再エントリ) のポイント
于 2009-04-18T20:34:54.320 に答える