2006-05-18
■ [Ruby] Rubyの「ブロック」再考

以前Rubyの「手続きオブジェクト」というエントリを書いたけど、「ブロック」はRubyのキモだから、もういちど復習するよ。
「ブロック」と「手続きオブジェクト」
Rubyには「コードの塊(かたまり)」「コードブロック」あるいは単に「ブロック」と呼ばれるものがあるよ(全部同じことを言っているよ。以下「ブロック」で統一するよ)。「ブロック」は「{」と「}」で囲むか、「do」と「end」で囲むことで表現できるよ。
たとえば
{ puts 'Hello, world!' puts 'Hello, world!' puts 'Hello, world!' }
とか、
do puts 'Hello, world!' puts 'Hello, world!' puts 'Hello, world!' end
とかを「ブロック」と呼ぶよ。
ただし「ブロック」はリテラルじゃないから、単にブロックだけをスクリプトに書いてもエラーになるよ。
そして「ブロック」は、Procクラスのインスタンスとしてオブジェクト化することができるよ。たとえば
hello = Proc.new { puts 'Hello, world!' puts 'Hello, world!' puts 'Hello, world!' }
とか、
hello = Proc.new do puts 'Hello, world!' puts 'Hello, world!' puts 'Hello, world!' end
とかだね。あと、こちらにあるとおり、Proc.newはprocやlambdaとも書くことができるよ。たとえば
hello = proc { puts 'Hello, world!' puts 'Hello, world!' puts 'Hello, world!' }
とか、
hello = lambda { puts 'Hello, world!' puts 'Hello, world!' puts 'Hello, world!' }
だね。そして手続きオブジェクトに対してcallメソッドを依頼すると、ブロックの中身を実行できるよ。
hello = lambda { puts 'Hello, world!' puts 'Hello, world!' puts 'Hello, world!' } hello.call
実行結果だよ。
Hello, world! Hello, world! Hello, world!
ブロックのパラメータ
ブロックは、パラメータをつけることで「手続き」だけでなく「関数」のようにふるまうことができるよ。パラメータは「|」で定義するよ。
「パラメータに2つの値を与えられたら、その二つを足し算するブロック」は、次のようになるよ。
{|x, y| x + y}
もちろん、Proc.new(やprocやlambda)で「手続きオブジェクト」にできるよ。
sum = lambda {|x, y| x + y}
「手続きオブジェクト」を使って関数計算させるには、パラメータに値を渡してcallしてあげればいいみたいだよ。
puts sum.call(2, 3)
Proc.new(やprocやlambda)で作った「パラメータ付きブロック」はオブジェクトだから、まるで「名前のない関数」のようだよね(変数名は便宜的につけているラベルなので、オブジェクトの名前ではない)。
ぼくは関数型言語のことはよく知らないけど、関数型言語で言う「無名関数」っていうのは、きっと「手続きオブジェクト」のようなものなんだろうねえ。
- バリケンのRuby日記 - [Ruby] Rubyの「クロージャ」...
- バリケンのRuby日記 - [Ruby] Rubyの「イテレータ」...
- バリケンのRuby日記 - [Ruby] 「再帰的な関数」を...
- バリケンのHaskell日記 - [Haskell] 関数型言語を勉...
- SHOW MUST GO ON - ブロックについて
- バリケンのHaskell日記 - [Haskell] コードブロック
- 只今Ruby勉強中 - ブロックについて
- バリケンのRuby日記 - [Ruby][Rails] ActiveSupport(2) - Sy...
- バリケンのRuby日記 - [Ruby] 最初に基礎を徹底的...
- バリケンのPython日記 - [Python] 制御構造(1)
- 半端でなく中途半端なJavaプログラマがRubyとJava...
- 橋本詳解 - lambdaを配列にとっておいてevent dispat...