2011-07-26 87 views
5

是否有任何快速的方式作爲PartialFunction[A, B]作爲具體功能(類型,如(A) => B)?最簡潔的語法,我知道的是:斯卡拉部分功能從具體的

(a: A) => a match { case obj => func(obj) } 

是否有隱式轉換的任何地方,像:

implicit def funcAsPartial[A, B](func: A => B) = new PartialFunction[A, B] { 

    def isDefinedAt(a: A) = true 
    def apply(a: A) = func(a) 

} 

我想我只是寫了什麼,我一直在尋找,但是這是否已經存在斯卡拉圖書館?

回答

5

使用隱式轉換來做到這一點很危險,因爲(A) => B不應該從PartialFunction[A, B]繼承。也就是說,PartialFunction的合約保證您可以安全*在isDefinedAt返回true的任何地方呼叫apply。 Function1的合同不提供這樣的保證。

如果將隱式轉換應用於未定義的函數,則隱式轉換會導致違反其合約的PartialFunction。相反,使用一個皮條客,使轉換明確:

implicit def funcAsPartial[A, B](f: A => B) = new { 
    /** only use if `f` is defined everywhere */ 
    def asPartial(): PartialFunction[A, B] = { 
     case a => f(a) 
    } 

    def asPartial(isDefinedAt: A => Boolean): PartialFunction[A, B] = { 
     case a if isDefinedAt(a) => f(a) 
    } 
} 

// now you can write 
val f = (i: Int) => i * i 

val p = f.asPartial // defined on all integers 
val p2 = f.asPartial(_ > 0) // defined only on positive integers 

*由於在評論中討論,也未必完全清楚什麼是「安全」是指這裏。我想到的方式是PartialFunction明確聲明其域名,如下所示:如果isDefinedAt對值x返回true,則可以按照與該函數作者的意圖一致的方式對apply(x)進行評估。那意味着apply(x)不會拋出一個異常,但僅僅是該異常是功能設計的一部分(應該記錄)。

+0

謝謝;我有一個誤解,即Function1暗示在整個域中定義。 –

+0

@AaronNovstrup:您對PartialFunction合同的解釋是唯一合理的解釋,但不會被ScalaDocs反映(至少在2.9.1之前)。 'PartialFunction'的ScalaDocs聲明:「PartialFunction [A,B]'類型的部分函數是一個一元函數,其中域不一定包含所有'A'類型的值。此外,他們從來沒有聲稱在任何定義的地方調用f是安全的(從某種意義上說),這很容易違反,正如'PartialFunction'文字'{case 0 => 1/0}'所做的那樣。 你從哪裏得到這些信息?是否需要提交錯誤報告? – Blaisorblade

+0

@Blaisorblade我相信當我在學習Scala時(這已經有一段時間了),我在郵件列表上看到了這個解釋,當我寫這個答案時我沒有看任何文檔。而且,是的,違反此合約很容易,甚至有點常見(例如,在catch塊中包裝/重新拋出異常)。真正的一點是,PartialFunctions定義了它們的域,而普通函數卻沒有(關於實際意義上的某些模糊性)。 –

0

不,我在幾個月前試圖找到一個,最後寫了我自己的,基本上和你的一樣。

+0

在我看來'(A)=> B'應該從'PartialFunction [A,B]'繼承,而不是相反。 –

+1

我同意這一點,理由是(總)函數是一個恰好被無處不在定義的部分函數(isDefinedAt(x)= true)。然而,馬丁奧德斯基說,一個函數不能保證是一個總函數,而只是它的域沒有記錄。所以PartialFunction是一個函數,它記錄了它的域。 –

+0

http://www.scala-lang.org/node/2750 –