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, когда пользователь вводит "false", код продолжается с my_check = false, и когда пользователь вводит буквенно-цифровую строку, которая не является ни "true", ни" false", то go функция завершает работу с 0.

Затем я попытался обернуть часть кода в блок try-catch (где находятся комментарии), и компиляция завершилась неудачей с:

Ошибка: найдено выражение cps в позиции не cps

Val my_check = try

Я понимаю, что есть проблема с "впрыскиванием" исключения в продолжение, но почему я не могу просто поместить смещенный вызов внутри блока try-catch?

Мне это нужно в рамках, которые я планирую, в которых программист не будет знать, что его код используется в форме продолжения (он вызовет некоторую функцию, которую он будет считать "нормальной", но на самом деле сделает shift).

Очевидно, мне нужно, чтобы он мог вызывать функцию внутри блока try-catch, даже если сам вызов shifted не вызовет исключения.

Можно ли решить эту проблему с помощью ControlContext ? Поможет ли это, если я добавлю некоторые правила "ввода" значений (возможно, с помощью @cps[..] )?

Я уже думал об альтернативе использования актеров, так что вы не получите никакого кредита за это:)

Спасибо,

(P. S. Я в Scala 2.9.2, и, очевидно, использовать -П:продолжения:включить флаг)

1 4

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, и код будет компилироваться.

Не спрашивайте меня, как или почему... Похоже на компиляцию вуду в мне...

Я не пробовал его на scala 2.10.