Я играю с каким-то DSL, определенным монадическим интерфейсом.
Так как применение монады, использующей кучу приложений flatMap, является довольно громоздким, и я нахожу для понимания синтаксически не столь красивым, я пытаюсь неявно смешивать монадический и немонодический код с использованием разграниченных продолжений.
Это действительно работает отлично, но я действительно не доволен этими типами, потому что я должен сдерживать себя в типе "Любой", чтобы сделать на компилируемом:( Таким образом, используя "Any" и "casting" позже, результат может привести к ошибкам во время выполнения...
Вот пример кода для смешивания Option-Monad в Scala с обычным кодом, поэтому вы можете видеть, о чем я говорю:
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: continue: включить BO.scala
и тест в Scala REPL:
scala> import BO._
scala> test4
res0: Option[Int] = Some(14)
scala> test5
res1: Option[Int] = None
Параметр-Monad запускается с использованием функции runOption (см. функции тестирования). Функции, вызываемые внутри runOption, могут использовать функцию get или метод значение, чтобы получить значение из Option. Если значение Нет, Monad немедленно остановится и вернет Нет. Таким образом, больше нет необходимости в сопоставлении шаблонов по значению типа Option.
Проблема заключается в том, что я должен использовать тип "Any" в runOption и для типа продолжения в get.
Можно ли выразить runOption и получить с типом rank-n в scala? Поэтому я могу написать:
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)
}
Спасибо!