lambda的なもの

個人的にあると結構便利なlambdaについて。
ちょっと前までRubyではlambdaが使えないと思ってたんだけど、ちゃんと使えることを知った。

irb(main):001:0> a = ["a", "b", "c"]
=> ["a", "b", "c"]
irb(main):002:0> a.map(&lambda{|x| x+"1"})
=> ["a1", "b1", "c1"]
irb(main):003:0> a.each(&method(:puts))
a
b
c
=> ["a", "b", "c"]
irb(main):004:0> a.map(&:capitalize)
=> ["A", "B", "C"]

なんだこれ・・・すごく便利っぽいぞ・・・!
002のlambdaは関数オブジェクト(class Procのインスタンス)を生成する構文で、&を付けてメソッドの引数にするとブロックとして渡されるらしい。まあ、ここまでは普通。
問題は003と004。これが何をやっているかというと、RubyではSymbolというクラスがあって、これがRubyにおけるシンボルを実行時に動的にいじれるようにしてくれるらしい。で、:putsとか:capitalizeとかいうのがSymbolオブジェクトの生成構文。そして、Symbolはto_procというメソッドを持っていて、こいつはそのシンボル名で表されるメソッドを呼び出すメッセージを投げるようなProcを返す。つまり、&:capitalizeとしてmapを呼び出すと:capitalize.to_procがmapに渡されて*1、これがaの各要素を引数としてProc.call()を呼び出される。ここで、第一引数はかレシーバになるので、結局"a"にcapitalizeをcallするメッセージを投げたことになり、"a".capitalizeとして処理される。
003のmethodはレシーバまでカプセル化したProcみたいな感じぽい。methodは厳密にはObjectクラスのメソッドで、Symbolを引数に取って、this.メソッド名をcallするようなProc類似のオブジェクト(Method)を返す。Rubyリファレンスマニュアルに書いてあるように、Objectはmodule Kernelをincludeしていて、putsはKernelのメソッドなので、結果的にはObject#putsになっているから結局this.method(:puts)でputsが使えるようになる。

Rubyすごいな・・・。

*1:メソッド呼出しで&を付けるとto_procしたものを渡す、でいいのか?