Ruby でクロージャ
クロージャってブロックとしてよく使っているが、何者なのかよくわかってなかった。
急に気になったので調べてみた。ただし Wikipedia。
クロージャ - Wikipedia
典型的には、クロージャはある関数全体が他の関数(以下、エンクロージャ)の内部で宣言されたときに発生し、内部の関数はエンクロージャのローカル変数(レキシカル変数)を参照する。実行時に外部の関数が実行された際、クロージャが形成される。クロージャは内部の関数のコードとエンクロージャのスコープ内の必要なすべての変数への参照からなる。
内部で宣言された関数は、宣言を行った関数内のローカル変数を参照できるってことかね。
サンプルコード
Wikipedia に 載ってた Javascript のカウンタを Ruby で書いてみた。
#!/usr/bin/env ruby def count i = 0 lambda {i += 1} end c1 = count 5.times do |i| puts c1.call end # >> 1 # >> 2 # >> 3 # >> 4 # >> 5
ちなみに関数の引数を利用することもできる。
#!/usr/bin/env ruby def count i lambda {i += 1} end c1 = count 0 5.times do |i| puts c1.call end
サンプルその2
これは間違いっぽい。
呼び出した関数のローカル変数ではなく、クラス内に値を保持してしまっているから。
やってることは似てるけど。
#!/usr/bin/env ruby class Hoge def initialize @x = 0 end def count return lambda{ @x += 1 } end end h = Hoge.new 5.times do |i| puts h.count.call end
ついでにカリー化
複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること。
クロージャよりもさっぱりだよ!!
サンプル
書いてみたはいいけどいまいち良さが理解できていない。
Wikipedia に出てきた除算関数
#!/usr/bin/env ruby def div x return lambda{|y| x / y} end d1 = div 10 puts d1.call 2 # >> 5
Ruby1.9 で
ラムダらむだ
#!/opt/local/bin/ruby1.9 def div x return ->(y){ x / y } end d1 = div 10 puts d1.(2)
さらに悪のりしてみる
λ
#!/opt/local/bin/ruby1.9 div = ->(x){ ->(y){ x / y } } puts div.(10).(2)
なははは。きもい!
なんか楽しくなってきた。
参考: Ruby 1.9の新しいλ式の文法がキモい件 - ’(rubikitch wanna be (a . lisper))