将Scala continuation用于非阻塞API

jua*_*ncn 11 continuations scala

我正在尝试使用Scala(2.9.0)延续来构建看似阻塞的API,但这实际上是异步的.假设你想写一些类似的东西:

if(ask("Continue?")) //Prompts Yes/No
  name = input("Enter your name")
Run Code Online (Sandbox Code Playgroud)

ask返回,当用户按下yes一个布尔,并input要求一个值.想象一下这是从Web服务器调用的,其中askinput不阻塞任何线程,它们只是在显示带有提示的页面(释放大多数资源)之前在Map(或会话,无关紧要)中存储延续.当响应返回时,它会查找Map中的延续并恢复代码.

到目前为止的问题是,我似乎无法找到一种合适的方法来定义askinput使用continuation而不将调用上下文的返回类型作为参数传递.

我得到的最接近的是:

#!/bin/sh
exec scala -P:continuations:enable -deprecation "$0" "$@"
!#
import util.continuations._

//Api code
def display[T](prompt: String) = shift {
  cont: (Unit => T) => {
        println(prompt)
        cont()
    }
}

//Client code
def foo() : Int = reset {
  display[Int]("foo!") // <-- how do I get rid of the type annotation?
  5
}

def bar() : Unit = reset {
  display[Unit]("bar!")
}

println(foo())
bar()
Run Code Online (Sandbox Code Playgroud)

我真的想摆脱调用的类型注释display.有谁知道实现这一目标的方法?只要客户端代码变得更简单,我就不在乎API定义是否变得更加丑陋.谢谢!

jua*_*ncn 6

我终于想通了:

#!/bin/sh
exec scala -P:continuations:enable -deprecation "$0" "$@"
!#
import util.continuations._

class Display(val resume: (Unit => Any)) extends Throwable

//Api code
def display(prompt: String) = shift {
  cont: (Unit => Any) => {
        println(prompt)
        throw new Display(cont)
    }
}

//Client code
def foo() : Int = reset {
  display("foo!")
  5
}

def bar() : Unit = reset {
  display("bar!")
}

//Framework
try {
    foo()
} catch {
    case d: Display => println(d.resume())
}

try {
    bar()
} catch {
    case d: Display => d.resume() 
}
Run Code Online (Sandbox Code Playgroud)

诀窍是接受返回的方法Any(Homeresque:D'oh!)并返回Nothing.

如果要实现返回值的内容,例如ask,您可以执行以下操作:

class Ask(val resume: (Boolean => Any)) extends Throwable

//Api code
def ask(prompt: String) = shift {
  cont: (Boolean => Any) => {
        println(prompt)
        throw new Ask(cont)
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,请求返回a Boolean.