ruby関数型プログラミング(3)lambda

★lambda
lambdaはProcとほぼ同じ働きがあります。lambdaとProc.newはどちらもProcクラスのインスタンス(手続きオブジェクト)を生成しますが、生成された手続きオブジェクトは、lambdaの生成する手続きオブジェクトのほうがよりメソッドに近い働きをするように設計されています。

具体的な違いは引数の扱いです。
lambdaのほうがより厳密です。引数の数が違っていると(メソッドのように)エラーになります。

Procで書く例

b1 = Proc.new{|a,b,c|
(a ? a : 0) + (b ? b : 0) + (c ? c : 0)
}
b1.call(2, 4, 6) # => 12
b1.call(2, 4) # => 6

lambdaで書く例

b2 = lambda{|a,b,c|
(a ? a : 0) + (b ? b : 0) + (c ? c : 0)
}
b2.call(2, 4, 6) # => 12
b2.call(2, 4)
ArgumentError: wrong number of arguments (given 2, expected 3)

続けて上のb1とb2のブロックを使うときも同じ挙動です。

def hoge
 yield 1,2
end
hoge(&b1)
=> 3
hoge(&b2)
ArgumentError: wrong number of arguments (given 2, expected 3)


また、Procとlambdaは、return文の挙動の違いがあります。次のようなm1とm2のメソッドを考えます。m1ではProcを使って1を返すブロックを呼んでいます。m2ではlambdaを使って2を返すブロックを呼んでいます。

def m1
  f = Proc.new {return 1}
  f.call
  100 
end

def m2
  f = lambda {return 2}
  f.call
  1000
end

m1 # => 1
m2 # => 1000

m1とm2それぞれのメソッドを呼び出すと、m1のProcのブロックのreturnではm1メソッド自体からも抜けています。だから100は返らないのです。
m2のlambdaのほうでは、returnしてもcallに戻りm2メソッド自体は抜けずに最後まで処理され1000が返ります。このようにProcでは呼び出し元のメソッドすらも処理を終わらせる挙動になり、lambdaは関数っぽく呼び出し元のcallの位置に復帰します。

ちなみにlambdaは->という構文でも同じことが書けます。

def m2
  f = -> {return 2}
  f.call
  1000
end

m2 # => 1000

これでも同じです。ブロック引数を持つ場合は、->の後に小括弧()で引数を与えます。

b2 = -> (a,b,c) {
(a ? a : 0) + (b ? b : 0) + (c ? c : 0)
}
b2.call(2, 4, 6)

以上のようにProcとlambdaの使い分けができるようになるとより関数型プログラミングが面白くなってくると思います。

この記事が気に入ったらサポートをしてみませんか?