为什么scala无法在部分方法中推断出类型?

时间:2011-08-19 17:58:12

标签: scala types partial-application

见这个例子:

def hello(a:String, b:String) = println(a + ":" + b)
val m1 = hello("aaa", _ )
m1("bbb")

无法编译,我需要将类型添加到partial方法:

val m1 = hello("aaa", _: String)

为什么scala不知道方法hello的第二个参数是String

3 个答案:

答案 0 :(得分:15)

Scala的类型推断是基于流的。方法和函数需要显式参数类型,用于推断其他类型。 参数类型不能从方法或函数体中推断出来。但是,有时参数类型是从外部上下文中获知的,因此不必标记。两个例子,

val f: String => Unit = hello("aaa", _)
val s = Seq(1,2).map(_+1) // Seq[Int].map expects a function of Int argument type

以下是Martin Odersky关于Scala类型推断与ML和Haskell相比的局限性的引用。挑战包括Scala的重载,记录选择和子类型,以及保持简单的需要,

  

Scala没有Hindley / Milner类型推断的原因是   很难与超载等功能结合使用   ad-hoc变体,而不是类型类),记录选择和子类型。   我不是说不可能 - 有许多扩展   结合这些功能;事实上,我一直对他们中的一些人有所了解   我。我只是说要很好地完成这项工作是非常困难的   练习,其中一个人需要有小型表达,而且好   错误消息。这也不是一个关闭案例 - 很多研究人员都是   努力推动这里的界限(例如在雷米看看   MLF)。但是现在它是更好的类型推理对比的权衡   更好地支持这些功能。你可以做出权衡   方法。我们想要与Java集成的事实倾向于扩展   支持亚型和远离欣德利/米尔纳。

来源:帖子Universal Type Inference is a Bad Thing下的评论。

答案 1 :(得分:4)

简单地说,Scala使用参数类型来搜索适当的方法,而不是方法类型来推断参数的类型。

要执行您想要的操作,必须使用两个参数搜索所有可能的hello调用,其中第一个String - 可能包含隐式转换 - 然后,如果找到一个最具体的选项,用它来推断第二个参数的类型。它必须对它已经完成的所有进行,减慢甚至更多已经是一个相当慢的编译速度。并非不可能,但它没有那样做。

答案 2 :(得分:3)

可能是因为此定义存在潜在的歧义,因为hello可能会过载。

// inside some class context
def hello(a:String, b:String) = println(a + ":" + b)
def hello(a:String, b:Int) = println(a + ":" + b.toString)
val m1 = hello("aaa", _ ) // which one to choose?

考虑到不仅是你能做val m1 = hello("aaa", _)的人。您的班级可能有val my_hello = (new C).hello("aaa", _)的用户。然后你通过在原始字符串hello方法中添加一个重载来破坏源代码兼容性,因为突然间它不再清楚应该做什么了。

我不确定这是唯一的原因,但我们当然可以将其视为安全措施。