我正在玩某种由单子接口定义的 DSL。
由于使用一堆 flatMap 应用程序来应用 monad 有点麻烦,而且我发现在语法上理解起来并不那么漂亮,所以我试图使用定界延续来隐式地混合 monadic 和非 monadic 代码。
它实际上工作正常,但我对这些类型真的不满意,因为我必须将自己限制在可编译的“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
并在 scala REPL 中进行测试:
scala> import BO._
scala> test4
res0: Option[Int] = Some(14)
scala> test5
res1: Option[Int] = None
Option-Monad 使用runOption函数运行(参见测试函数)。在runOption中调用的函数中调用的函数可以使用get函数或value方法从Option中获取值。如果值为None,Monad 将立即停止并返回None。因此不再需要对Option类型的值进行模式匹配。
问题是,我必须在runOption中使用“Any”类型并在get中使用延续的类型。
是否可以在 scala中表达runOption并使用 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)
}
谢谢!