Scala の継続を試してみる

前回の Scala 勉強会 in 渋谷 で [twitter:@cooldaemon] さんが発表していた Scala の継続の話を聞いて、とても気になったので Scala の継続を見てみる。
継続についてのお話にインスパイアされて Scala の継続を見てみる。
Scala の継続は限定継続と言うらしい。
細かいことは こちら 参照。
おおざっぱに言うと、継続する範囲を限定して継続が使えると言うことらしい。

参考 Scala の限定継続(Delimited Continuations) - なんとなくな Developer のメモ

試したソース

import scala.util.continuations.{reset, shift}
import scala.actors.Actor.{self, actor}

def main()
{
  println("start %s".format(self)) // (1)

  val result = reset {

    val x = shift {ctx : (Int => Int) =>
      {
        Thread.sleep(10)
        println("call/cc") // (2)

        val c = ctx(ctx(10)) // この呼び出して shift の次の処理 (nextShift) へ

        println("c %s".format(c))

        println("cont") // (3)
        
        c + 1 // この式の値が reset の結果となる
      }}

    // nextShift

    println("x %s".format(x)) 

    println("shiftted %s".format(self)) // (4)

    x*2 // このブロックを抜けると ctx の呼び出し元に戻る
  }

  println("result %s".format(result)) // (5)

  println("finish %s".format(self))
}


main()

実行結果

実行する際は -P:continuations:enable として継続プラグインを有効にしてやる必要がある。

$ scala -P:continuations:enable cont.scala
start scala.actors.ActorProxy@194d372
call/cc
x 10
shiftted scala.actors.ActorProxy@194d372
x 20
shiftted scala.actors.ActorProxy@194d372
c 40
cont
result 41
finish scala.actors.ActorProxy@194d372

処理の流れとしては
1 -> 2 -> 4 -> 4 -> 3 -> 5
となっている。

reset で継続範囲を指定し、 shift で継続を生成する。
shift は Scheme で言うところの call-with-current-continuation(call/cc) にあたる。

大体の流れはコメントに書いたので省略。

これを使うと actor を使わなくても この ネタをより自然に書けそうなので書いてみようと思う。