2011-07-27 79 views
11

我正在嘗試使用Scala(2.9.0)延續來構建看似阻塞的API,但實際上它是異步的。假設你希望寫類似:對非阻塞API使用Scala延續

if(ask("Continue?")) //Prompts Yes/No 
    name = input("Enter your name") 

ask,當用戶按下是返回一個布爾值,並input請求的值。從網絡服務器調用這個圖片,其中askinput不會阻塞任何線程,它們只是在顯示包含提示的頁面(釋放大部分資源)之前將一個延續存儲在一個Map(或會話中,無關緊要) 。當迴應回來時,它會查找地圖中的延續並恢復代碼。

到目前爲止的問題是,我似乎無法找到一個合適的方式來定義askinput使用continuations而不傳遞調用上下文的返回類型作爲參數。

我得到的最接近的是做這樣的事情:

#!/bin/sh 
exec scala -P:continuations:enable -deprecation "$0" "[email protected]" 
!# 
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定義是否越來越醜,只要客戶端代碼變得更簡單。 謝謝!

+2

將答案發布爲答案。 –

+0

不知道我可以! – juancn

回答

6

我終於想通了:

#!/bin/sh 
exec scala -P:continuations:enable -deprecation "$0" "[email protected]" 
!# 
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) 
    } 
} 

在上面的代碼,請回報Boolean