Ruby の callcc(継続)

Ruby 2.2 から非推奨になってしまった callcc(継続)ですが…。

callcc は goto みたいなものです。

callcc {|cnt| ..}

とあるとき、継続 cnt が call されると、callcc {|cnt| ..} の「後へ」処理が移ります。メソッド call に引数があった場合は、それが callcc {|cnt| ..} の返り値になります。cnt は状態を保存していると同時に、ラベルみたいなものですね。なので、一度 callcc {} が出現しないともちろんそこへジャンプすることはできません。

なので、無限ループは簡単です。

c = nil
callcc {|cnt| c = cnt}
c.call

これで無限ループします。

ループから抜けます。

callcc do |cnt|
  n = 0
  loop do
    puts n
    n += 1
    cnt.call if n > 10
  end
end

 
メソッドからの脱出。

def a(cnt)
  puts "inner 1"
  cnt.call("jump")
  puts "inner 2"
end

puts callcc {|cnt| a(cnt)}

結果。

inner 1
jump

 
メソッド再帰からの脱出もできます。

def a(n, cnt)
  cnt.call(n) if n > 9
  a(n + 1, cnt)
end

puts callcc {|cnt| a(0, cnt)}    #=>10