バリケンのRuby日記 RSSフィード

2006-05-18

[] Rubyの「ブロック」再考  Rubyの「ブロック」再考 - バリケンのRuby日記 を含むブックマーク はてなブックマーク -  Rubyの「ブロック」再考 - バリケンのRuby日記  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.newproclambdaとも書くことができるよ。たとえば

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(やproclambda)で「手続きオブジェクト」にできるよ。

sum = lambda {|x, y| x + y}

「手続きオブジェクト」を使って関数計算させるには、パラメータに値を渡してcallしてあげればいいみたいだよ。

puts sum.call(2, 3)

Proc.new(やproclambda)で作った「パラメータ付きブロック」はオブジェクトだから、まるで「名前のない関数」のようだよね(変数名は便宜的につけているラベルなので、オブジェクトの名前ではない)。

ぼくは関数型言語のことはよく知らないけど、関数型言語で言う「無名関数」っていうのは、きっと「手続きオブジェクト」のようなものなんだろうねえ。