Scala Continuations - Почему мой сдвинутый вызов не может быть внутри блока try-catch?
Я новичок в продолжениях Scala и относительно новичок в языке Scala в целом.
Я попытался поиграть с продолжениями Scala и написал следующий код:
case class MyException(msg:String) extends Exception
def go:Int = reset {
println("enter your input")
val my_check = //try
{
val user_input = readLine()
if (!user_input.matches("\\w+")) {
throw new MyException("illegal string: " + user_input)
}
shift {
k: (Boolean => Int) => {
if (user_input == "true") {
k(true)
}
else if (user_input == "false") {
k(false)
}
else {
// don't even continue
0
}
}
}
}
// catch {
// case MyException(msg) => false
// }
if (my_check) {
println("TRUE")
1
}
else {
println("FALSE")
-1
}
}
println(go)
Код работал должным образом: когда пользователь вводит не буквенно-цифровую строку MyException
выдается, когда пользователь вводит "true", код продолжается с my_check = true
когда пользователь вводит "ложь", код продолжается с my_check = false
и когда пользователь вводит буквенно-цифровую строку, которая не является ни "истинной", ни "ложной", go
функция выходит с 0.
Затем я попытался обернуть часть кода в блок try-catch (где есть комментарии), и компиляция завершилась неудачно:
ошибка: найдено выражение cps в позиции не cps
val my_check = попробуй
Я понимаю, что есть проблема с "внедрением" исключения в продолжение, но почему я не могу просто поместить сдвинутый вызов в блок try-catch?
Мне нужно это в рамках, которую я планирую, в которой программист не будет знать, что его код используется в форме продолжения (он вызовет некоторую функцию, которую он считает "нормальной", но на самом деле сделает shift
).
Очевидно, мне нужно, чтобы он мог вызывать функцию внутри блока try-catch, даже если сам сдвинутый вызов не вызовет исключения.
Можно ли решить эту проблему с помощью ControlContext? Поможет ли это, если я добавлю некоторые "правила" для значений (возможно, с помощью @cps [..])?
Я уже думал об альтернативе использования актеров, чтобы вы не получили за это никакой оценки:)
Спасибо,
(PS Я использую Scala 2.9.2 и, очевидно, использую флаг -P: продолжений: включить)
1 ответ
Спасибо @som-snytt, но ваше решение было несколько далеко от общего. Я не могу требовать от пользователя фреймворка писать def my_check
вместо val my_check
каждый раз, когда он использует блок try-catch.
Однако я поиграл с вашим решением и создал следующий код:
import scala.util.continuations._
case class MyException(msg:String) extends Exception
object try_protector {
def apply[A,B](comp: => A @cps[B]):A @cps[B] = {
comp
}
}
object Test extends App {
def go: Int = reset {
println("enter your input")
val my_check = try_protector {
try {
val user_input = readLine()
if (!user_input.matches("\\w+")) {
throw new MyException("illegal string: " + user_input)
}
shift {
k: (Boolean => Int) => {
user_input match {
case "true" => k(true)
case "false" => k(false)
case _ => 0
}
}
}
} catch {
case MyException(msg) => false
}
}
if (my_check) {
println("TRUE")
1
} else {
println("FALSE")
-1
}
}
println(go)
}
И это работает! (на Scala 2.9.2)
Пользователь просто должен обернуть свой блок try-catch try_protector
и код скомпилируется.
Не спрашивайте меня, как или почему... Это похоже на компиляцию VODOU для меня...
Я не пробовал это на Scala 2.10.