2014-10-02 54 views
4

使用下面的语法与钻营启用定义功能:柯里在斯卡拉:多参数列表和回访功能

def sum(x: Int)(y: Int)(z: Int) = x + y + z 

一个仍然有_,以后缀来的sum令行禁止呼叫任何电话:

sum _ 
sum(3) _ 
sum(3)(2) _ 

否则编译器会报错。

于是我使出:

val sum = (x: Int) => (y: Int) => (z: Int) => x + y + z 

它没有_工作。

现在的问题是:为什么多参数列表版本需要_为了让咖喱来踢?为什么这两个版本的语义在所有上下文中都不相同?

另外,是后者的版本莫名其妙吗?它是否受到任何警告?

+3

http://stackoverflow.com/questions/4915027/two-ways-of-currying-in-scala-whats-the-use-case-for-each/4916606#4916606 – Debilski 2014-10-02 12:51:43

回答

4

这两种语义不同的原因是方法和功能不是一回事。

方法是全功能的JVM方法,而函数是值(即类的实例,如Function1,Function2等)。

所以

def sum(x: Int)(y: Int)(z: Int) = x + y + z 

val sum = (x: Int) => (y: Int) => (z: Int) => x + y + z 

看似相同,但首先是一种方法,而第二个是Function1[Int, Function1[Int, Function1[Int, Int]]]

当您尝试使用一种方法,其中一个函数值是预期的,编译器会自动将其转换为函数(称为eta-expansion的进程)。

但是,在某些情况下,编译器不会自动扩展这些方法,例如您明确想要部分应用它的案例。

使用_触发eta扩展,所以一个方法转换为函数,并且每个人都很高兴。

按照Scala的规范,你也可以注释预期的类型,在这种情况下自动进行扩展:

def sum(x: Int)(y: Int)(z: Int) = x + y + z 
val sumFunction: Int => Int => Int => Int = sum 

这是一样的道理,为什么

def sum(x: Int, y: Int) = x + y 
List(1,2,3).reduce(sum) 

作品,即我们传递了一个明确需要函数的方法。

这里的时候斯卡拉执行ETA膨胀的更深入的讨论:https://stackoverflow.com/a/2394063/846273


关于其选择采用,我会指出你this answer,这是非常详尽的。

+0

我只是不明白为什么如果我做了像'val x = foo _'这样的东西,编译器会需要'_' - 它是否认为我可能忘记将正确数目的参数传递给'foo'?至于你的答案的其余部分,我已经知道所有要点:) – 2014-10-02 16:04:22

+0

这是一个相当随意的设计决定。从scala规范中,您可以传递'_'或明确注释类型('val x:Int => Int => Int => Int = sum')。这里有一个相关的讨论:http://stackoverflow.com/questions/2363013/in-scala-why-cant-i-partially-apply-a-function-without-explicitly-specifying-i – 2014-10-02 16:09:02