Scala连续 - 为什么我的转移呼叫不能在try-catch块中? [英] Scala Continuations - Why can't my shifted call be inside a try-catch block?
问题描述
我尝试使用Scala连续播放,并写下了以下代码: p>
case class MyException(msg:String)extends异常
def go:Int = reset {
println(输入你的输入)
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 {
//甚至不继续
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
我知道有一个问题是注入一个例外到一个延续,bu t为什么我不能简单地把转移的电话放在try-catch块中?
我在规划的框架中需要这个,程序员不会意识到他的代码以连续的形式使用(他会调用一些函数他认为正常,但实际上会执行 shift
)。
显然,我需要他能够调用try-catch块中的函数,即使转移的调用本身也不会引发异常。
可以通过 ControlContext 一>?
如果我在值上添加了一些打字规则(可能是使用 @cps [..] ),那么它会有帮助吗?
<我已经考虑过使用演员的选择,所以你不会得到任何信用的:)
谢谢,
(PS我正在使用Scala 2.9.2,显然使用 -P:继续:启用标志)
谢谢@ som-snytt,但是你的解决方案与一般的解决方案有所不同。我不能要求框架用户在每次使用try-catch时写入 def my_check
而不是 val my_check
但是,我使用您的解决方案,并构建了以下代码:
code> import scala.util.continuations._
case class MyException(msg:String)extends异常
对象try_protector {
def apply [A ,B](comp:=> A @cps [B]):A @cps [B] = {
comp
}
}
对象测试扩展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 {
casetrue=> k(true)
casefalse=> 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上尝试过。
I'm new to Scala continuations, and relatively new to the scala language in general.
I tried playing with Scala continuations and wrote the following code:
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)
The code worked as expected: when the user enters a non-alphanumeric string a MyException
is thrown, when the user enters "true" the code continues with my_check = true
, when the user enters "false" the code continues with my_check = false
, and when the user enters an alphanumeric string which is not "true" nor "false" the go
function exits with 0.
Then I tried wrapping some of the code in a try-catch block (where the comments are), and the compilation failed with:
error: found cps expression in non-cps position
val my_check = try
I understand there's a problem with "injecting" an exception into a continuation, but why can't I simply put the shifted call inside a try-catch block?
I need this in the framework I'm planning, in which the programmer will not be aware that his code is used in a continuation form (he'll call some function which he would think to be "normal", but will actually do the shift
).
Obviously, I need him to be able to call the function inside a try-catch block, even though the shifted call itself will not raise an exception.
Can this issue be solved with ControlContext? Will it help if I add some "typing" rules on the values (maybe with the @cps[..])?
I already thought about the alternative of using Actors so you won't get any credit for that :)
Thanks,
(P.S. I'm using Scala 2.9.2, and obviously use the -P:continuations:enable flag)
Thanks @som-snytt, but your solution was somewhat far from a generic one. I can't demand the framework user to write def my_check
instead of val my_check
every time it uses a try-catch block.
However, I played with your solution, and built the following code:
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)
}
And it works! (on scala 2.9.2)
The user just has to wrap his try-catch block with a try_protector
and the code will compile.
Don't ask me how or why... It looks like compilation VODOU to me...
I haven't tried it on scala 2.10.
这篇关于Scala连续 - 为什么我的转移呼叫不能在try-catch块中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!