ブロック・Proc・Lambda

かつて(5年くらい前?)はまったくわからなかったブロックです.
しばらくRubyから離れて,JSで非同期処理のコールバックを扱うようになって,またRubyを始めて(,以前も現在も趣味ですが),そうしたら理解できたと思うので備忘録も兼ねてまとめた.

Ruby

Ruby: 2.2.2

ブロックの例

メソッド側は,明示的に受け取る仮引数とかは用意しない.

ブロックは yield で実行する.ブロックが引数を受け取る場合(例の場合 s )は yield に渡す.
ブロックが与えれたかは block_given? で true/false でチェックする.つまりブロックは1つしか与えられない.

def say(s)
  yield "Nice to meet you, #{s}" if block_given?
end

puts "ブロックの例"
say do |s|
  puts s
end

Proc

ブロックではなく Proc である.故にブロックと同じ使い方はできないが,似ている.とても似ている.
ブロックは変数に保存できないが, Proc はそれが出来る.なのでブロック使いまわしたいなあなんて時は Proc を使う.

Proc の実行は,Procオブジェクトの call メソッドを呼ぶ.

# Proc

## Procの実行方法
p = proc do |s|
  puts s
  #return   # NG: かつては return 命令は可能だったようだが.
  #s        # OK
  #next     # OK
  next s    # OK: if分岐等で呼び出し元に値を返したい場合これが良い
end
val = p.call "Hello, Proc"    # => "Hello, Proc"
puts "Proc returns: #{val}"   # => "Proc returns: Hello, Proc"

## Procをメソッドの引数として渡す方法
def do_block(block)
  block.call "Yes!"
end

p = proc do |s|
  puts "私はProcです.#{s}"
end

do_block(p)    # => "私はProcです.Yes!"

Lambda(ラムダ)

Lambda は Proc とほぼ同じだが,基本的に return なのでうれしい気がする.
一般的には Proc と Lamdba のどちらなのだろう?

## Lambdaの実行方法
l = lambda do |s|
  puts s
  return s
end
val = l.call "Hello, Lambda"    # => "Hello, Lambda"
puts "Lambda returns: #{val}"   # => "Lambda returns: Hello, Lambda"

## Lambdaを引数として渡す方法
l = lambda do |s|
  puts "私はLambdaです.#{s}"
end

do_block(l)    # => "私はLambdaです, Yes!"
               # Rubyはダックタイピングなので do_block で Proc も Lambda も扱える! Nice!

lambda の別記法

Lambda には別に記法がある.
なんの役に立つのかは知らない.

l = -> (s) do
  puts s 
  return s
end
val = l.call "Hello, Another Lambda"    # => "Hello, Another Lambda"
puts "Another Lambda returns: #{val}"   # => "Another Lambda returns: Hello, Another Lambda"

まとめ

ブロック・Proc・Lambdaを理解してたのしいRubyライフ!