Scala中的Currying:多个参数列表与返回函数

时间:2014-10-02 12:47:59

标签: scala functional-programming parameter-passing currying

使用以下语法定义启用了currying的函数时:

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

否则编译器会抱怨。

所以我求助于:

_

没有_

现在的问题是:为什么多参数列表版本需要{{1}}以便进行curry?为什么这两个版本的语义在所有上下文中都是等价的呢?

此外,后一版本是否有些气馁?是否有任何警告?

1 个答案:

答案 0 :(得分:4)

这两个语义不同的原因是方法和函数不是一回事。

方法是完全成熟的JVM方法,而函数是值(即Function1Function2等类的实例。)

所以

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)

有效,即我们传递的方法明确要求函数。

以下是对scala执行eta扩展的更深入的讨论:https://stackoverflow.com/a/2394063/846273


关于选择采用哪种方法,我会指出this answer,这是非常详尽的。