限定継続を実現するScalaコンパイラプラグインを試してみる
現在、Scalaでファーストクラスの継続を扱うことはできないが、Scala 2.8からは、コンパイラプラグインという形で、限定継続(Delimited Continuation)を扱う機能が提供されることになっている。2.8は未だリリースされていないが、Scala 2.8のnightly buildと、コンパイラプラグインのソースをリポジトリから入手すれば、限定継続の機能を試してみることができるようだ。
というわけで、試してみた(参考:http://blog.richdougherty.com/2009/02/delimited-continuations-in-scala_24.html)。
- Scala 2.8のnightly buildをダウンロード
- Delimited Continuationを実現するコンパイラプラグインをリポジトリから入手
>svn co http://lampsvn.epfl.ch/svn-repos/scala/compiler-plugins/continuations/trunk continuations
- コンパイラプラグインをビルド
>cd continuations >set ANT_OPTS=-Xmx512m >ant test
ここで、なんか
error: jsr166y.RecursiveAction does not take type parameters [scalac] FJTaskWrapper.runOnCurrentThreadOrPool(new RecursiveAction[Uni t] {
というエラーが発生。RecursiveActionは型パラメータとらねーよ、と言うことらしいのでソースをいじってnew RecursiveAction { ... }に書き換えて、もう一回ビルドしてみる。
(略)\continuations\doc\examples\continuations\Test17Webserver.scala:32: error: value jcl is not a member of package collection [scalac] import scala.collection.jcl.Conversions._ [scalac] ^ (略)\continuations\doc\examples\continuations\Test9.scala:24: error: type mismatch; [scalac] found : xs.type (with underlying type scala.collection.mutable.It erable[A]) [scalac] required: examples.continuations.Test9.Monadic[A,scala.collection.m utable.Iterable] [scalac] implicit def reflective[A](xs:Iterable[A]) = new Reflective[A,Iterable](xs) [scalac] ^ (略)\continuations\doc \examples\continuations\Test9.scala:35: error: value reflect is not a member of List[java.lang.String] [scalac] List(left.reflect[Any] -> right.reflect[Any]) [scalac] ^ [scalac] three errors found
とりあえず、試すのには支障無さそうなので、エラーが出たdoc\examples\以下のソースは全部リネームして、再度ビルド。
>ren doc\examples\continuations\Test9.Scala Test9.scala.bak >ren doc\examples\continuations\Test17Webserver.scala Test17Webserver.scala.bak
なんかことごとくテストが失敗するが、エラーメッセージからするに、たぶんクラスパス関係の設定が足りてないのだと思われる。とりあえず、気にせずに先に進む。
[partest] Compiling and running files [partest] testing: [...]\files\run\example4.scala [FAILED] [partest] testing: [...]\files\run\example5.scala [FAILED] [partest] testing: [...]\files\run\example6.scala [FAILED] [partest] testing: [...]\files\run\example2.scala [FAILED] [partest] testing: [...]\files\run\example0.scala [FAILED] [partest] testing: [...]\files\run\example3.scala [FAILED] [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main" [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main" [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main" [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main" [partest] testing: [...]\files\run\example1.scala [FAILED] [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main" [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main" [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main" [partest] testing: [...]\files\run\basics.scala [FAILED] [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main" [partest] testing: [...]\files\run\example7.scala [FAILED] [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main" [partest] testing: [...]\files\run\example8.scala [FAILED] [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main" [partest] testing: [...]\files\run\example9.scala [FAILED] [partest] example9.scala:6: error: value Test9 is not a member of package exam ples.continuations [partest] examples.continuations.Test9.main(args) [partest] ^ [partest] one error found [partest] testing: [...]\files\run\match0.scala [FAILED] [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main" [partest] testing: [...]\files\run\match1.scala [FAILED] [partest] java.lang.NoClassDefFoundError: and [partest] Exception in thread "main"
- 限定継続を使ったサンプルプログラムを書く
提供されているのは、オーソドックスなshift/resetなので、それを使って簡単なサンプルプログラムを書いてみる。以下のプログラムは、150,200,250が順に表示される事を意図している。
import scala.continuations.ControlContext._ object UseShiftReset { def main(args: Array[String]) { var k: Int => Int = null println(reset { shift{_k: (Int => Int) => k = _k 150 } + 50 }) println(k(150)) println(k(200)) } }
- サンプルプログラムをコンパイルする。
- -Xpluginでコンパイラプラグインを指定するのと、クラスパスに限定継続を使うときに必要なライブラリを指定するのを忘れずに。
>%SCALA_HOME%\bin\scalac -Xplugin:build\pack\selectivecps-plugin.jar -classpath build\build.library UseShiftReset.scala
- サンプルプログラムを実行する。
>%SCALA_HOME%\bin\scala -Xplugin:build\pack\selectivecps-plugin.jar -classpath build\build.library;. UseShiftReset 150 200 250
無事、意図通りの結果が表示された。