give IT a try

プログラミング、リモートワーク、田舎暮らし、音楽、etc.

ラムダ(lambda)を使ったアキュムレータ(累積器)

今読んでる「ハッカーと画家」にこんなRubyのサンプルコードが載ってました。

def foo(n)
  lambda {|i| n += i}
end


本の解説によるとこれは「数nを取り、『数iを取ってnをiだけ増加させ、その増加した値を返す関数』を返す関数」というアキュムレータ(累積器)だそうです。


本を読んだだけではピンとこなかったので実際に動かしてみました。

def foo(n)
  lambda {|i| n += i}
end
 
x = foo 1
p x.call 1
p x.call 2
p x.call 3
p x.call 0
p x.call -1


実行結果は以下の通りです。

2
4
7
7
6


これを見てどういうプログラムか分かりましたか?
僕は実行結果を見てもしばらく意味がわかりませんでした・・・。


が、よく見るとこういうことだったんですね。

x = foo 1 #初期値が1
p x.call 1 #1+1=2
p x.call 2 #2+2=4
p x.call 3 #4+3=7
p x.call 0 #7+0=7
p x.call -1 #7-1=6


前の計算の値がxの中に保持されているイメージです。
なんか意外ですね。


lambdaについてもうちょっと調べてみようと「プログラミング言語Ruby」を読んでいたところ、Ruby1.9ではlambdaの新しい構文がサポートされたと書いてありました。
その構文を使って最初のコードを書き直してみました。

def foo(n)
  ->(i){n += i}
end
 
x = foo 1
p x.call 1
#以下略


fooの定義までlambdaにしてしまうとこんな感じです。

foo = ->(n){->(i){n += i}}
 
x = foo.call 1
p x.call 1
#以下略


メソッドが終了した後の変数の保持については「プログラミング言語Ruby」の「6.6 クロージャ」のあたりに詳しく書いてあります。
まあ正直、このあたりは難しすぎて完全には理解できていないですけどね・・・。(- -;;


こんなコードを実務で書く機会はほとんどないでしょうが、動きが面白かったので載せてみました。
ご参考までに。

参考文献


プログラミング言語 Ruby

プログラミング言語 Ruby