2016-09-21 56 views
2

有人可以解释为什么r1类型是:(String => String, String)但是r2类型是String => (String, String)?谢谢。scala - 部分应用函数的元组类型

def f1(n: String, m: String): String = m + n 
val f2: String => String = f1(_, "something") 
val r1: (String => String, String) = f2 -> "foo" 
val r2: String => (String, String) = f1(_, "something") -> "foo" 

回答

0

即使在阅读Jatin的回答后,有些事情让我感到困惑。这是我进一步研究后的发现。请注意,为了节省输入,我不在左侧使用类型归属,并让Scala来推断。

def f1(n: String, m: String): String = m + n 

// f1: (n: String, m: String)String 

val f2 = f1(_, "something") 

通常,强调在“表达”表示,其是由编译器适当扩大匿名函数。如果编译器找不到合适的'下划线'参数类型,它会像下面这样抱怨:

// <console>:12: error: missing parameter type for expanded function ((x$1) => f1(x$1, "something"))  

val f2 = f1(_:String, "something") // Specifiying the type of the `_` as `_:String` fixes the missing parameter type error above. 

// f2: String => String = <function1> 

val r1 = f2 -> "foo" 
// r1: (String => String, String) = (<function1>,foo) 

现在是重要的东西。为什么下面的行不会给出与上面的r1相同的结果!!!在underscore scoping rules.

val r2 = f1(_:String, "something") -> "foo" 
// r2: String => (String, String) = <function1> 

其原因在于由丹尼尔出色答卷据丹尼尔回答的第1章,匿名函数的范围将包括整个右侧的表达。所以上面的扩展匿名函数将

(x:String) => f1(x:String, "something") -> "foo" 

这给函数签名字符串=>(字符串,字符串)

为了解决这个问题,我们使用的第二个规则索布拉尔的答案和限制)由包围所述f1表达(绑定到_匿名函数或{},像下面的范围:

val r3 = (f1(_:String, "something")) -> "foo" 
r3: (String => String, String) = (<function1>,foo) 

现在,我们得到相同的结果作为val r1 = f2 -> "foo"

+0

谢谢。现在对我来说很有意义。 – limuhob

3

让我们来看看在place holder语法会发生什么匿名函数:

val f2: String => String = f1(_, "something") 

其展开:(x$1: String) => f1(x$1, "something")"(先从scala -Xprint:typer您REPL)

随着f2 -> "foo",它只是变得(f2,"foo")和因此(String => String, String)

f1(_, "something") -> "foo",其被评估为:

(x:String) => f1(x,"something") -> foo 
(x:String) => (f1(x,"something") , foo) 
(String => (String, String)) 

如果占位符的原因首先评估的混乱呢?

评估占位符并在编译时调整树。与->一样,由于ArrayAssoc隐含,所以在运行时将其评估为元组a。

+0

嗯谢谢! – limuhob