私は、モナディックインターフェイスによって定義されたある種のDSLで遊んでいます。
一連のflatMapアプリケーションを使用してモナドを適用するのはちょっと面倒で、構文的にはそれほど美しくないので、区切られた継続を使用してモナドコードと非モナドコードを暗黙的に混合しようとしています。
実際には正常に機能していますが、コンパイル可能にするために「Any」タイプに自分自身を制限する必要があるため、タイプには本当に満足していません:(。したがって、後で結果が得られたときに「Any」と「casting」を使用します。必要な場合、ランタイムエラーが発生する可能性があります。
これは、ScalaのOption-Monadを通常のコードと混合するためのコードの例です。これにより、私が話していることがわかります。
object BO {
import scala.util.continuations._
def runOption[C](ctx: => Any @cpsParam[Option[Any],Option[Any]]): Option[C] = {
val tmp : Option[Any] = reset {
val x : Any = ctx
Some(x)
}
tmp.asInstanceOf[Option[C]]
}
def get[A](value:Option[A]) = shift { k:(A=>Option[Any]) =>
value.flatMap(k)
}
class CPSOption[A](o:Option[A]) {
def value = get[A](o)
}
implicit def opt2cpsopt[A](o:Option[A]) = new CPSOption(o)
def test1 = runOption[Int] {
val x = get(None)
x
}
def test2 = runOption[Int] {
val x = Some(1).value
x
}
def test3 = runOption[Int] {
val x = Some(1)
val y = Some(2)
x.value + y.value
}
def test_fn(x:Option[Int], y:Option[Int], z:Option[Int]) = runOption[Int] {
x.value * x.value + y.value * y.value + z.value * z.value
}
def test4 = test_fn(Some(1), Some(2), Some(3))
def test5 = test_fn(Some(1), None, Some(3))
}
次のコマンドでコードをコンパイルします:$ scalac -P:continuations:enable BO.scala
そしてscalaREPLでテストします:
scala> import BO._
scala> test4
res0: Option[Int] = Some(14)
scala> test5
res1: Option[Int] = None
Option-Monadは、runOption関数を使用して実行されます(テスト関数を参照)。runOption内で呼び出される関数は、 get関数またはvalueメソッドを使用して、 Optionから値を取得できます。値がNoneの場合、モナドはすぐに停止し、Noneを返します。したがって、 Option型の値でパターンマッチングを行う必要はありません。
問題は、runOptionで「Any」タイプを使用し、 getで継続のタイプを使用する必要があることです。
runOptionを表現してscalaでrank-n型を取得することは可能ですか?だから私は書くことができます:
def runOption[C](ctx: forall A . => A @cpsParam[Option[A], Option[C]]) : Option[C] =
...
def get[A](value:Option[A]) = shift { k:(forall B . A=>Option[B]) =>
value.flatMap(k)
}
ありがとう!