我正在尝试使用Scala(2.9.0)延续来构建看似阻塞的API,但这实际上是异步的。假设您要编写类似以下内容的内容:
if(ask("Continue?")) //Prompts Yes/No
name = input("Enter your name")
如果用户按"is",则
ask
返回一个 bool 值,而input
要求输入一个值。从Web服务器调用此图片,其中ask
和input
不会阻塞任何线程,它们只是在显示带有提示的页面(释放大部分资源)之前在Map(或 session ,没什么大不了)中存储一个延续。 。当响应返回时,它会在Map中查找延续并恢复代码。到目前为止的问题是,我似乎无法找到一种合适的方法来定义
ask
和input
以使用延续而不将调用上下文的返回类型作为参数传递。我得到的最接近的东西是这样的:
#!/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()
我真的很想摆脱对
display
的调用中的类型注释。有人知道实现这一目标的方法吗?只要客户端代码变得更简单,我都不在乎API定义是否变得更丑陋。谢谢!
最佳答案
我终于想通了:
#!/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()
}
诀窍是接受返回
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)
}
}
在上面的代码中,ask返回一个
Boolean
。