Scala Continuations - Why can't my shifted call be inside a try-catch block?

I am new to Scala sequels and relatively new to Scala in general.

I tried playing with a sequel to Scala 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 not an alphanumeric string, but 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 that is not true or false, the go function exits from 0.

Then I tried to wrap part of the code in a try-catch block (where there are comments), and the compilation failed with

error: found cps expression in non-cps position

val my_check = try

I understand that there is a problem with โ€œinjectingโ€ the exception into the continuation, but why can't I just put the shifted call inside the try-catch block?

I need this in the structure that I plan, in which the programmer will not know that his code is used in the form of a continuation (he will name some function that he will consider "normal", but will actually perform a shift ).

Obviously, I need it so that it can call the function inside the try-catch block, even if the shifted call itself will not throw an exception.

Can this problem be solved with a ControlContext ? Did he help if I add some โ€œtypingโ€ rules for values โ€‹โ€‹(possibly with @cps [..])?

Iโ€™ve already thought about an alternative to using Actors, so you wonโ€™t get any credit for this :)

Thanks,

(PS I am using Scala 2.9.2 and obviously using -P: continue: enable flag)

+4
source share
1 answer

Thanks @ som-snytt, but your solution was a bit far from general. I cannot require the framework user to write def my_check instead of val my_check every time he 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 needs to wrap the try-catch block with try_protector and the code will be compiled.

Do not ask me how and why ... It seems like compiling VODOU for me ...

I have not tried this on scala 2.10.

0
source

Source: https://habr.com/ru/post/1437046/


All Articles