procとlambdaの違いについてメモ

Rubyのメモ。
procとlambdaはどちらもProcクラスのインスタンスなのだけど、違いがある。
そもそものProcの使い方と、lambdaとprocとで何が違うのかを調べてみました。


プログラミング言語Ruby」によると、

procはブロックのオブジェクト形態であり、ブロックのように振る舞う。lambdaは少し動作が異なり、ブロックというよりメソッドに近い。

らしい。

Procの実行方法

まず実行方法。
Procの実行方法はcall以外にも配列アクセス演算子やcallを呼び出すシンタックスシュガーがある。

#!/usr/bin/env ruby
f = Proc.new {|x,y| x*y }

# 以下の書き方は全て同じ意味(Ruby1.9以降)
p f.call(2,3)  # 6

# [] 配列アクセス演算子
p f[2,3]        # 6

# .() シンタックスシュガー
p f.(2,3)       # 6

lambdaリテラル

通常のlambdaの書き方

incre = lambda {|x| x+1 }
p incre.call(2)

lambdaリテラル

incre = ->(x){ x+1 }
p incre.call(2)

どちらも同じ意味になる

チェック方法

lambdaとprocのチェックをするには、 lambda? を使う。

先ほどのコードに以下を追加

l = ->(x,y){ x*y }
p l.call(2,3)   # 6

# lambdaかどうかのチェック
p f.lambda?   # false
p l.lambda?   # true

returnを使う場合

proc内でreturn文を使うとprocに変換されたブロックを囲うメソッドから戻ろうとする。
lambdaの中のreturn文は、lambda自身から戻る。

def make_proc(msg)
  Proc.new { p msg; return }
end

def test_proc
  p "start test_proc."
  proc_obj = make_proc("I'm proc.")
  proc_obj.call      #この行は実行されない
  p "end test_proc."
end

begin
  test_proc
rescue => e
  p e  # <LocalJumpError: unexpected return>
end

def make_lambda(msg)
  lambda { p msg; return }
end

def test_lambda
 p "start test_lambda."
 lambda_obj = make_lambda("I'm lambda.")
 lambda_obj.call   #実行される
 p "end test_lambda."
end

test_lambda

Procへの引数渡し

procはyieldと同様のセマンティクスを使う

p = Proc.new {|x,y| print x,y }
p.call(1)
p.call(1,2)
p.call(1,2,3)
p.call([1,2])

余分な引数は捨てられ、足りない値はnilになる。


lambdaはメソッドと同じく宣言した数と同じ引数を渡して呼び出す必要がある。

l = lambda {|x,y| print x,y }
l.call(1,2)
l.call(1)         # ArgumentError
l.call(1,2,3)   # ArgumentError
l.call([1,2])    # ArgumentError
l.call(*[1,2])  # *による明示的な展開があるためエラーにならない

参考:プログラミング言語Ruby

プログラミング言語 Ruby

プログラミング言語 Ruby