Scala Continuations - 为什么我的转移调用不能在try-catch块内?

时间:2012-09-30 14:47:31

标签: scala exception-handling try-catch continuations try-catch-finally

我是Scala延续的新手,对scala语言来说相对较新。

我尝试使用Scala continuation并编写以下代码:

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-catch块中?

我在我计划的框架中需要这个,程序员不会意识到他的代码是以延续形式使用的(他会调用一些他认为是“正常”的函数,但是会实际上做shift)。

显然,我需要他能够在try-catch块中调用该函数,即使移位的调用本身不会引发异常。

ControlContext可以解决此问题吗? 如果我在值上添加一些“输入”规则(可能使用 @cps [..] )会有帮助吗?

我已经考虑过使用Actors的替代方案,因此你不会得到任何荣誉:)

谢谢,

(P.S。我正在使用Scala 2.9.2,显然使用 -P:continuations:enable 标志)

1 个答案:

答案 0 :(得分:0)

谢谢@ som-snytt,但你的解决方案与通用解决方案有些差距。每次使用try-catch块时,我都不能要求框架用户编写def my_check而不是val my_check

但是,我使用了您的解决方案,并构建了以下代码:

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_protector包装他的try-catch块,代码就会编译。

不要问我怎么或为什么......看起来像编辑VODOU给我......

我没有在scala 2.10上尝试过。