2012-06-20 22 views
4

我發佈這個問題出於好奇,看看有人知道如何模式匹配在以下情況下工作。假設我有一個函數值定義如下:Scala部分應用功能與模式匹配

val f = (s: String) => s.toInt 

它的類型當然是String => Int。現在我想創建一個基於模式匹配任何傳遞給該函數的輸出的新函數。我可以定義如下:

val f2 = f(_: String) match { 
    case i: Int => i + 2 
} 

現在我的新功能也從string =>詮釋,但它的過程中增加了2。它可以被稱爲如下:

scala> f2("3") 
res0: Int = 5 

如果我這樣做而不做局部的應用程序,然後我得到一個基於函數本身匹配:

val f3 = f match { 
    case x => "matched: " + x 
} 

現在值F3被分配「相匹配<函數1 >「,因爲它調用與'f'匹配的值。

所以我的問題是,斯卡拉怎麼區分這兩個?它們都是函數值,都是String => Int類型。事實上,如果我跑比賽之前分配部分應用函數值給一個臨時變量TMP,那麼它的行爲一樣F3:

val tmp = f(_: String) 
val f4 = tmp match { 
    case x => "matched: " + x 
} 

現在F4被分配的而不是一個函數「<功能1 >匹配的」 String => Int。

我可以看到想要做的任何一個的價值,我只是好奇它是如何完成的。這是否只是一些魔術斯卡拉補充說,它不知何故它會發現你在比賽中部分應用了一個功能,所以它會產生不同的東西...

回答

9

這就是下劃線的工作原理。

f(_: String) match { 
    case i: Int => i + 2 
} 

(x: String) => (f(x) match { 
    case i: Int => i + 2 
}) 

的簡寫(括號內添加,使事情更加清楚),但你的另一例子是相當於

(x: String => f(x)) match { 
    case y => "matched: " + y 
} 
+0

不知道我確信。在第二個例子中,函數值f只是一個值,所以不需要做(x:String => f(x))match {..}。事實上,在比賽結束前,任何地方都沒有任何價值x。這種情況只是匹配類型(String => Int)的值,所以f匹配{...}就足夠了。我買了第一個例子。這意味着val tmp =(x:String)=> f(x)然後傳遞給匹配。 – Mike

+0

@Mike不需要eta展開f,但f在功能上等價於它的eta展開(x:String => f(x))。他說它們是等價的,而不是編譯器實際將它們轉換成的東西。 –

+0

好的,我現在同意(x:String => f(x))等價於f,它們都是String => Int。這也意味着我可以用'f __'來替換f以觸發手動eta擴展,並且它仍然可以像在f3中那樣工作(在REPL中嘗試它並且事實上是這樣)。所以我想這個故事的寓意是'f_'和f(_:String)不是等價的,即使對於一般的函數應用它們的行爲是一樣的。 – Mike