2012-07-18 93 views
2

我在想這可能是無形的庫。用函數替換異步匿名類

我正在使用無形來將匿名類轉換爲閉包。這需要使用來自FnHListerAux特徵的hlisted

我想要做的就是擺脫傳入的虛擬函數,並返回與此函數具有相同類型簽名的閉包,如F。如果沒有異步執行的匿名類,這很容易。有沒有辦法解決這個問題?

def async[F, A <: HList, R](
    shell: Shell, 
    success: F, 
    failure: FunctionTypes.Failure, 
    dummy: F)(implicit h: FnHListerAux[F, A => R], 
      u: FnUnHListerAux[A => R, F]): F = 
{ (args: A) => 

    require(shell != null, "Shell cannot be null") 
    require(shell.getDisplay() != null, "The shell must have a display") 

    val display = shell.getDisplay() 
    display.asyncExec(new Runnable() { 
    def run(): Unit = { 
     try { 
     success.hlisted(args) 
     } catch { 
     case e: Throwable => 
      failure(e) 
     } 
    } 
    }) 

    dummy.hlisted(args) 
}.unhlisted 
+0

如果你需要像這樣的無意義的東西,你的算法必定會有一些嚴重的問題。試着解釋你需要什麼。 – 2012-07-18 00:45:26

+0

當然,這是一個好主意。我對Scala很陌生。我仍然很好奇,看看你是否真的可以取代一個函數的主體。但是,對於我的實際問題,解決方案很可能存在於不成形的圖書館中,這超出了我的知識水平,我仍然試圖理解它的本質。 – Hakkar 2012-07-18 00:58:03

回答

3

我首先簡化一下。假設我有一個功能f。事先我不知道它是什麼樣的,我不在乎它返回的是什麼。我想用一些功能來包裝它,並獲得具有相同參數類型的函數。我也不在乎這個結果函數返回什麼,所以我不妨將它返回Unit

你可以寫類似下面的功能一堆(當然,22):

def wrap[A](f: A => Unit): A => Unit = ??? 
def wrap[A, B](f: (A, B) => Unit): (A, B) => Unit = ??? 
def wrap[A, B, C](f: (A, B, C) => Unit): (A, B, C) => Unit = ??? 

但你不想。

無形的,絕對可以幫你解決這個問題更一般:

def wrap[F, A <: HList](f: F)(
    implicit h: FnHListerAux[F, A => Unit], u: FnUnHListerAux[A => Unit, F] 
): F = { (args: A) => 
    println("Before!"); f.hlisted(args); println("After!") 
}.unhlisted 

這給了我們:

scala> def f(i: Int, s: String) { println(s * i) } 
f: (i: Int, s: String)Unit 

scala> val wf = wrap(f _) 
wf: (Int, String) => Unit = <function2> 

scala> wf(3, "ab") 
Before! 
ababab 
After! 

注意f可以返回其他的東西比Unit,這將仍然工作,因爲一切在斯卡拉是一個UnitFunctionN特徵協調在他們的返回類型。

運用這種方法來驗證碼,我們得到如下:

def async[F, A <: HList](
    shell: Shell, success: F, failure: FunctionTypes.Failure 
)(
    implicit h: FnHListerAux[F, A => Unit], u: FnUnHListerAux[A => Unit, F] 
): F = { (args: A) => 
    require(shell != null, "Shell cannot be null") 
    require(shell.getDisplay() != null, "The shell must have a display") 

    val display = shell.getDisplay() 
    display.asyncExec(new Runnable() { 
    def run(): Unit = { 
     try { 
     success.hlisted(args) 
     } catch { 
     case e: Throwable => 
      failure(e) 
     } 
    } 
    }) 
}.unhlisted 

無需dummy

+0

再次感謝特拉維斯:) – Hakkar 2012-07-18 21:39:04