为什么scala不能推断部分应用中省略参数的类型?

时间:2012-10-11 16:59:29

标签: scala type-inference currying partial-application

考虑一下:

scala> def sum(x:Int,y:Int) = x+y
sum: (x: Int, y: Int)Int

scala> sum(1,_:String)
<console>:9: error: type mismatch;
 found   : String
 required: Int
              sum(1,_:String)

显然,Scala非常了解_sum(1,_)的确切类型,但必须 say sum(1,_:Int)。为什么?

显然Scala随机(?)选择一个:

scala> def sum(x:Int,y:String) = 1
sum: (x: Int, y: String)Int

scala> def sum(x:Int,y:Double) = 1
sum: (x: Int, y: Double)Int

scala> class Ashkan
defined class Ashkan

scala> sum(1,_:Ashkan)
<console>:10: error: type mismatch;
 found   : Ashkan
 required: Double
              sum(1,_:Ashkan)

3 个答案:

答案 0 :(得分:1)

从这个issue来看,听起来他们可以做到这一点,但对于一般情况来说,它相对于它提供的好处来说太复杂了。一般情况下复杂的原因是重载方法的可能性。如果您还有:

def sum (x : Int , y : Double ) = x + y

在范围内,如果没有类型规范,你的意思是不明确的。在没有超载的情况下,类型推断很容易解决,但我觉得他们觉得为特定情况提供它是不值得的。

简而言之,听起来它是实用的,而不是理论上的限制。

我相信错误消息是通过简单地使用适当的名称和arity抓取第一个函数生成的,在非重载函数的情况下会给人一种完全推理出类型的印象。

答案 1 :(得分:1)

我建议它是“好书”中这个侧栏或盒子的延伸,它表达了最低惊喜原则:

http://www.artima.com/pins1ed/functions-and-closures.html#8.7

或者让我们不要把它称之为“最少的惊喜”,而是两个惊喜中的较小者。

考虑以下情况,您要求编译器在两个继承的函数之间进行选择。如果适用正常的重载规则,它将选择子类中定义的方法。但这是一个好政策吗?

scala> class Foo {
     | def f(x: Int, y: Int) = x + y
     | }
defined class Foo

scala> class Bar extends Foo {
     | def f(x: Int, y: String) = x + y.toInt
     | }
defined class Bar

scala> class Baz extends Bar {
     | val f = super.f(1, _) // overloading says f(Int,String), did you mean it?
     | }

在面向对象的世界中,有太多方法让自己感到惊讶,因此需要缴纳一小笔税。理智税。

(请注意,在此示例中,可能会重载分辨率,但要求您指定f(1, _: MyWhatever),我们已经定义了适用性的含义。)

答案 2 :(得分:0)

this question的答案是否为你揭开了它的光芒?它似乎是一种不一致,正如@oxbow_lakes'answer所示。