scala - 具有部分应用函数的元组类型

时间:2016-09-21 10:56:13

标签: scala types

有人可以解释为什么r1类型是:(String => String, String)但是r2类型是String => (String, String)?谢谢。

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"

2 个答案:

答案 0 :(得分: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。

答案 1 :(得分:0)

即使在阅读了贾丁的回答之后,某些事情让我感到困惑。经过一些进一步的研究,这是我的发现。注意,为了节省输入,我没有在左侧使用Type ascriptions,让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相同的结果!原因在于Daniel在underscore scoping rules.

的出色回答
val r2 = f1(_:String, "something") -> "foo"
// r2: String => (String, String) = <function1>

根据Daniel回答的第一条规则,匿名函数的范围将包括整个右侧表达式。所以上面扩展的匿名函数将是

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

其中给出了函数签名String =&gt; (String,String)

为了解决这个问题,我们在Sobral的答案中使用了第二条规则,并通过用{)括起_表达式来限制绑定到f1的匿名函数的范围。 {},如下所示:

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

现在,我们得到与val r1 = f2 -> "foo"

相同的结果