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

複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること。

クロージャよりもさっぱりだよ!!

サンプル

書いてみたはいいけどいまいち良さが理解できていない。
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))