Непоследовательное поведение в платформе Scala CPS
Я пытаюсь создать сопрограммную платформу для пакетной выборки данных, проходя через каждую зависимую от данных функцию параллельно. Вот что у меня так далеко: http://pastie.org/7147798
Это не работает
def get(id: Long) = reset { // Is it not already cached? if (!cached.isDefinedAt(id)) { // Store the ID we want to fetch. queued += id // Come back later... shift { fetch[Object]() } : Seq[Any] @cps[ExecState[Object]] } // We should have the ID fetched now. Result(cached(id)) }
Я получаю следующую ошибку
ashoat@ashoatmbp [~/project]# scala -P:continuations:enable Loader.scala /Users/ashoat/project/Loader.scala:134: error: type mismatch; found : Unit required: Any @util.continuations.package.cps[Main.$anon.Loader.ExecState[Main.$anon.Loader.Object]] if (!cached.isDefinedAt(id)) { ^ one error found
Это работает
def get(id: Long) = reset { // Is it not already cached? if (!cached.isDefinedAt(id)) { // Store the ID we want to fetch. queued += id // Come back later... shift { fetch[Object]() } : Seq[Any] @cps[ExecState[Object]] // We should have the ID fetched now. Result(cached(id)) } else { // We should have the ID fetched now. Result(cached(id)) } }
Это не работает
val getFive = reset { if (true) { Result(5) } else { val seq: Seq[Any] = shift { fetch[Int](Object.get(15181990251L)) } val Seq(obj: Object) = seq Result(obj.fields("test").toInt) } }
Я получаю следующую ошибку
ashoat@ashoatmbp [~/project]# scala -P:continuations:enable Loader.scala /Users/ashoat/project/Loader.scala:170: error: cannot cps-transform expression new this.Loader.Result[Int](5): type arguments [this.Loader.Result[Int],this.Loader.Result[Int],Nothing] do not conform to method shiftUnit's type parameter bounds [A,B,C >: B] Result(5)// : Result[Int] @cps[Result[Int]] ^ one error found
Это работает
val getFive = reset { if (true) { Result(5) : Result[Int] @cps[Result[Int]] } else { val seq: Seq[Any] = shift { fetch[Int](Object.get(15181990251L)) } val Seq(obj: Object) = seq Result(obj.fields("test").toInt) } }
Но я получаю следующее предупреждение
ashoat@ashoatmbp [~/project]# scala -P:continuations:enable Loader.scala /Users/ashoat/project/Loader.scala:170: warning: expression (new this.Loader.Result[Int](5): this.Loader.Result[Int]) is cps-transformed unexpectedly Result(5) : Result[Int] @cps[Result[Int]] ^ one warning found 8
1 ответ
Хотя я все еще не совсем понимаю продолжения, насколько я могу судить, ключевая проблема в вашем примере заключается в том, что ваш код не всегда предоставляет shift
к reset
,
Компилятор ожидает найти некоторые shift
вложенный в reset
, Затем CPS преобразует shift
в ControlContext][A, B, C]
и код, который происходит после shift
в ControlContext.map
вызов.
Потому что у вас есть if
утверждение, в случае, когда берется ветвь else, нет вложенного shift
:
reset {
if (false) {
shift { ... }
}
Result(cached(id)) // no shift
}
То же самое с
reset {
if (false) {
shift { ... }
} else {
Result(cached(id)) // no shift
}
}
Это не может быть преобразовано в действительный код CPS.
Похоже, вы могли бы выполнить сброс внутри ветви if или предоставить тривиальный оператор shift для ветви else:
if (!cached.isDefinedAt(id)) reset {
shift { ... }
Result(cached(id))
} else {
Result(cached(id))
}
// or
reset {
if (!cached.isDefinedAt(id)) {
shift { ... }
Result(cached(id))
} else {
shift[Result[Object], ExecState[Object], ExecState[Object]] { k =>
Result(cached(id))
}
}
}
Изменить: Кажется, есть некоторые несоответствия о том, как плагин CPS выводит типы. Например:
var b = false
def test[A](a: A) = reset {
if (b) {
a
} else {
shift{ (k: Unit => A) => k() }
a
}
}
Запуск компиляции с -Xprint:selectivecps
Параметры показывают, что компилятор выводит тип как Reset[A, Nothing]
тогда выполнение кода приведет к ошибке во время выполнения. Если if обращено как:
var b = false
def test[A](a: A) = reset {
if (b) {
shift{ (k: Unit => A) => k() }
a
} else {
a
}
}
Тогда компилятор правильно делает вывод reset[A, A]
, Если я предоставлю параметры типа для reset
лайк test[A](a: A) = reset[A, A] {
тогда это работает в обоих случаях.
Может быть, указав параметры типа для reset
а также shift
а также вместо использования Result(5)
, с использованием shiftUnit[A, B, C]
Метод поможет уменьшить несоответствия.