Scala の限定継続(Delimited Continuations)

Scala 2.8 では、限定継続(Delimited Continuations)という機能がサポートされる模様。
個人的に、この継続っていう機能の概念がイマイチよく分からなかったので実際に使ってみた。

  • Scala 2.8 Beta1
  • continuations プラグイン

事前準備

Scala 2.8 Beta1 で限定継続の機能を使用するには別途プラグインを使う必要があるので、まず Subversion を使って以下のソースを checkout し、Ant を使ってビルドしておく。

continuations プラグインビルド例
>ant

なお、Ant でビルドするには環境変数 SCALA_HOME の設定が必要なので注意。(plugin.properties を変更しても可)

ビルドすると build/pack ディレクトリに以下の JAR ファイルが作成されるので、

  • selectivecps-library.jar
  • selectivecps-plugin.jar

以下のように scala コマンドの実行時にこれらを指定すれば、限定継続の機能が使用できるようになる。

実行例
>scala -Xplugin:selectivecps-plugin.jar -classpath selectivecps-library.jar sample.scala

Scalaの限定継続

Scala の限定継続では reset と shift を使用し、reset の範囲内で shift 後の処理が継続の対象となる。

以下のサンプルでいうと、継続 k は (1) 〜 (2) の範囲の処理にあたる。

sample.scala
import scala.continuations.ControlContext._

println("before reset")

val res = reset {
    println("before shift")

    val a = shift {k: (Int => Int) =>
        println("before k ")
        val i = k(k(1))
        println("after k : " + i)
        i
    } +1 //(1)

    println("after shift : " + a)
    a * 2 //(2)
}
println("after reset : " + res)

これを実行すると以下のようになる。

実行結果
>scala -Xplugin:selectivecps-plugin.jar -classpath selectivecps-library.jar sample.scala
before reset
before shift
before k
after shift : 2
after shift : 5
after k : 10
after reset : 10

なぜ、このような結果になるかというと。
k(1) の処理内容は以下のようになり、結果が 4 となる。

  1. a = 1 + 1
  2. println("after shift : 2")
  3. 戻り値 2 * 2

結果、k(k(1)) は k(4) となり、結果が 10 になる。

  1. a = 4 + 1
  2. println("after shift : 5")
  3. 戻り値 5 * 2


先程は reset の中で shift を使っていたが、以下のように処理を分けても同様の動作となる。継続 k は (1) 〜 (2) の範囲の処理にあたる。

sample2.scala
import scala.continuations.ControlContext._

def foo = {
    println("start foo")

    val res = shift {k: (Int => Int) => 
        println("shift start")

        k(k(1))
    } + 1 //(1)

    println("end foo = " + res)
    res
}

def bar = {
    println("start bar")

    val res = foo * 2
    println("end bar = " + res)
    res //(2)
}

println("result = " + reset(bar))
実行結果
>scala -Xplugin:selectivecps-plugin.jar -classpath selectivecps-library.jar sample2.scala
start bar
start foo
shift start
end foo = 2
end bar = 4
end foo = 5
end bar = 10
result = 10