Обработка исключений вокруг смены в Scala
Scala 2.10.2. Бег
import util.continuations._
import concurrent.ops._
object Main {
def main(args: Array[String]) {
reset {
try {
shift { cont: (Unit => Unit) => {
spawn {
throw new Exception("blah")
cont()
}
}}
println("after shift")
} catch {
case e: Exception => println(e)
}
println("reset end")
}
}
}
дает
Cont.scala:16: error: type mismatch;
found : Unit
required: Unit @scala.util.continuations.cpsParam[Unit,Unit]
case e: Exception => println(e)
^
one error found
Если я уберу блок try/catch, все будет хорошо. Я все еще пытаюсь понять, как продолжения работают в Scala, но это полностью ускользает от меня.
2 ответа
Просто констатирую очевидное - это вывод типа Scala, который встречает проблему cps-аннотации. Блок catch не содержит аннотированного выражения cps. В этом случае ожидается, что catch-блок будет того же типа, что и try-block:
Unit @cps[Unit] // same as Unit @cpsParam[Unit,Unit]
По моему опыту, вывод типов и CPS-преобразование в Scala не всегда работают должным образом, а вещи, которые работают в одной версии Scala, не работают в другой версии.
Существуют обходные пути, такие как try_protector, упомянутый в продолжениях Scala. Почему мой сдвинутый вызов не может быть внутри блока try-catch?
Не уверен, поможет ли это в вашем случае (например, версия Scala 2.10.2).
Вы намерены использовать оператор try/catch Exception("blah")
?
Даже если это скомпилировано, spawn
что устарело, произойдет в другом потоке до того, как поток запустит продолжение.
Без try/catch у вас есть что-то вроде этого:
println("in main " + Thread.currentThread())
reset {
shift { cont: (Unit => Unit) =>
{
spawn {
println("in spawned " + Thread.currentThread())
cont()
}
}
}
println("after shift " + Thread.currentThread())
println("reset end")
}
}
cont
функция - это часть кода, которая соответствует этой функции:
val cont = () => {
println("after shift " + Thread.currentThread())
println("reset end")
}
Итак, когда вы делаете spawn { cont() }
Вы просто запускаете два println
в новой отдельной теме. Запустив программу, я получаю:
in main Thread[main,5,main]
in spawned Thread[Thread-1,5,main]
after shift Thread[Thread-1,5,main]
reset end
Это показывает, что продолжение выполнялось в отдельном потоке. Теперь, если вы вставите throw new Exception()
до cont()
, тогда все, что вы получите - это исключение, созданное в порожденном потоке (где, очевидно, исключение будет проглочено).
Будет ли запуск продолжения внутри try/catch и возникнет исключение после shift
больше того, что вы пытаетесь сделать?
reset {
shift { cont: (Unit => Unit) =>
spawn {
println("in spawned " + Thread.currentThread())
try { cont() }
catch { case e: Exception => println(e) }
}
}
println("after shift " + Thread.currentThread())
throw new Exception("blah")
println("reset end")
}
}
Это печатает:
in main Thread[main,5,main]
in spawned Thread[Thread-1,5,main]
after shift Thread[Thread-1,5,main]
java.lang.Exception: blah