2015-04-30 30 views
5

我有以下Scala代碼:斯卡拉Function.tupled VS f.tupled

def f(x: Int, y: Int): Option[String] = x*y match { 
    case 0 => None 
    case n => Some(n.toString) 
} 

val data = List((0, 1), (1, 0), (2, 3), (4, -1)) 

data flatMap {case (x, y) => f(x, y)} 

但是,最後一行是太冗長,所以我嘗試了所有的這些,沒有他們的編譯。

data flatMap f

data flatMap f.tupled

data flatMap Function.tupled(f)

data flatMap {f _}

data flatMap (f _).tupled

data flatMap f(_)

我在做什麼錯了?唯一可行的事情是這樣的:

(data map Function.tupled(f)).flatten

我想到了一個map其次flatten總是可以通過flatMap所取代,不過雖然上面的行編譯,這並不:

data flatMap Function.tupled(f)

回答

2

當您返回Options時,您只能使用flatMap,因爲隱含的從OptionIterable的轉換由隱含的option2Iterable 。您的List[(Int, Int)]上的方法flatMap需要從(Int, Int)GenTraversableOnce[Int]的功能。編譯器無法將隱式轉換標識爲可行的選項。你可以幫助編譯器一起通過明確的通用參數:

import Function._ 
data.flatMap[String, Iterable[String]](tupled(f)) 
//Or 
data flatMap tupled[Int, Int, Iterable[String]](f) 

同樣的想法的其他製劑也可以讓編譯器來選擇正確的類型和implicits,即使沒有明確的仿製藥:

data flatMap (tupled(f _)(_)) 
data.flatMap (f.tupled(f _)(_)) 

最後,你可能還需要與collectunlift這裏一起玩,它可以表達這種邏輯,以及一個不錯的方式:

data collect unlift((f _).tupled) 
data collect unlift(tupled(f)) 

Function.unlift採用返回Option的方法,並將其變爲PartialFunction,該方法與原函數返回None的位置不匹配。 collect接受部分函數並收集部分函數的值,如果它在每個元素處定義的話。

+0

'數據收集unlift(tupled(f))'在這裏更有意義IMO。謝謝! – pathikrit

0

爲進一步非常有用的答案上面,如果你使用collect,你就可以走了一步,並重寫你的函數f的部分功能:

val f: PartialFunction[(Int, Int), String] = { 
    case (x, y) if x*y != 0 => (x*y).toString 
} 

然後,您可以這樣處理你的數據:

data collect f 

通常,任何返回選項的函數都可以重寫爲部分函數。在某些情況下,由於您的表達式數量較少,因此不需要在Some()中包含返回值。