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

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

ошибка: найдено выражение cps в позиции, отличной от cps

val my_check = попробовать

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

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

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

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

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

Спасибо,

(P.S. Я использую Scala 2.9.2 и, очевидно, использую флаг -P:continuations:enable)


person Oren    schedule 30.09.2012    source источник
comment
Награда будет выдана за нахождение решения, а не только за объяснение, почему это невозможно сделать...   -  person Oren    schedule 02.10.2012
comment
Я попытался подумать об определении некоторого ctry ccatch, который пользователь моего фреймворка будет использовать вместо стандартного try and catch, но я действительно запутался. Такое решение также будет учитываться в награду :)   -  person Oren    schedule 02.10.2012


Ответы (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)
}

И это работает! (на скале 2.9.2)

Пользователь просто должен обернуть свой блок try-catch try_protector, и код скомпилируется.

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

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

person Oren    schedule 04.10.2012