Обработка исключений вокруг смены в 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
Другие вопросы по тегам