2016-05-18 39 views
1

我想拿出一個組合子,讓我做這樣的事情:適配器一個PartialFunction

def pfAdapter(pf: PartialFunction[String, String]): PartialFunction[(String,String), String]) = { 
    case (a,b) if(pf.isDefinedAt(a)) => pf(a) 
} 

基本上,我有一個Map[String, String],想使用它作爲一個PartialFunction採用兩個參數 - 忽略第二個元素,並將第一個元素用作關鍵字。

上述方法的工作原理,但我不喜歡pf本質上得到兩次評估(可能沒有辦法),並且它不是「優雅」的事實...我想知道是否有一些那種我不知道的combinator會讓我做點像{ _._1 } andThen pf。顯然,這最後一次嘗試不起作用,因爲它的結果總是被定義的,並且只會在不存在的鍵上失敗,我只是用它作爲我正在尋找的解決方案理想狀態下的示例。

想法,任何人嗎?

+0

因此,如果密鑰不存在,您可以處理異常情況?或者我錯過了什麼? –

+0

不,我想要一個PartialFunction,它是在元組上定義的,它們的第一個元素作爲map中的一個鍵存在。沒有例外:) – Dima

+0

那麼它是如何部分?當第一個元素不存在時,期望的結果是什麼? –

回答

2

函數本身(pf.apply)是不是真的兩次評估,但其isDefinedAt與您定義的成功匹配兩次評估。這意味着在初始PartialFunctionpf評估兩次unapply -s和警衛。

順便說存在Scalaz一個組合子,做了類似的事情:pf.first.andThen(_._1),但它基本上等同於你的定義。

你可以寫一個小測試,看看是否pf.isDefinedAt是兩次評估,並與pfAdapter幾種可能的實現運行它:

object Unapply { 
    def unapply(s: String): Boolean = { 
    println(s"unapplying on $s") 
    s == "1" 
    } 
} 

val m = Map("1" -> 1, "2" -> 2) 
def pf: PartialFunction[String, String] = { 
    case Unapply() => "11" 
} 

def pfAdapter1[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] = 
    Function.unlift((t: (A, T)) => pf.lift(t._1)) 

def pfAdapter2[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] = 
    new PartialFunction[(A, T), B] { 
    def isDefinedAt(arg: (A, T)) = pf.isDefinedAt(arg._1) 
    def apply(arg: (A, T)) = pf(arg._1) 
    } 

def pfAdapter3[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] = { 
    case (a,b) if pf.isDefinedAt(a) => pf(a) 
} 

def pfAdapter4[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] = { 
    import scalaz.Scalaz._ 
    pf.first.andThen(_._1) 
} 

println(m collect pfAdapter1(pf)) 
println(m collect pfAdapter2(pf)) 
println(m collect pfAdapter3(pf)) 
println(m collect pfAdapter4(pf)) 

和執行該代碼如下結果:

unapplying on 1 
unapplying on 2 
List(11) 
unapplying on 1 
unapplying on 1 
unapplying on 2 
List(11) 
unapplying on 1 
unapplying on 1 
unapplying on 2 
List(11) 
unapplying on 1 
unapplying on 1 
unapplying on 2 
List(11) 

所以第一次執行pfAdapterFunction.unlift((t: (A, T)) => pf.lift(t._1))實際上確實避免兩次評估isDefinedAt

這工作,因爲Map.collectPartialFunction.applyOrElse實現,併爲applyOrElse狀態的文檔,即:

對於所有的部分功能文本編譯器生成的 applyOrElse實現避免了模式 匹配器和雙評估警衛。這使得applyOrElse爲 高效實現許多操作和場景,如基礎:

...

  • 電梯和unlift不會在每次調用兩次評估輸出功能
+0

感謝您指向'.unlift',我不知道它。 – Dima