【发布时间】:2011-04-07 01:57:02
【问题描述】:
我正在使用由单子接口定义的某种 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 中使用 rank-n 类型来表达 runOption 和 get ? 所以我可以写:
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)
}
谢谢!
【问题讨论】:
标签: scala monads continuations