Scala 中的柯里化:多个参数列表与返回函数

Eri*_*lun 7 functional-programming scala parameter-passing currying

当使用以下语法定义启用柯里化的函数时:

def sum(x: Int)(y: Int)(z: Int) = x + y + z
Run Code Online (Sandbox Code Playgroud)

仍然需要在任何对柯里化调用的调用后加上sumwith 的后缀_

sum _
sum(3) _
sum(3)(2) _
Run Code Online (Sandbox Code Playgroud)

否则编译器会抱怨。

所以我采取了:

val sum = (x: Int) => (y: Int) => (z: Int) => x + y + z
Run Code Online (Sandbox Code Playgroud)

无需_.

现在的问题是:为什么需要多参数列表版本_才能启动柯里化?为什么这两个版本的语义在所有上下文中都不相同?

另外,后一个版本是否会受到某种阻碍?它有任何警告吗?

Gab*_*lla 8

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

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

所以

def sum(x: Int)(y: Int)(z: Int) = x + y + z
Run Code Online (Sandbox Code Playgroud)

val sum = (x: Int) => (y: Int) => (z: Int) => x + y + z
Run Code Online (Sandbox Code Playgroud)

可能看起来相同,但第一个是方法,而第二个是Function1[Int, Function1[Int, Function1[Int, Int]]]

当您尝试使用需要函数值的方法时,编译器会自动将其转换为函数(称为 eta 扩展的过程)。

但是,在某些情况下,编译器不会自动对方法进行 eta 扩展,例如您公开的情况,您明确希望部分应用它。

使用_会触发 eta 扩展,因此方法会转换为函数,每个人都很高兴。

根据 scala 规范,您还可以注释预期类型,在这种情况下会自动执行扩展:

def sum(x: Int)(y: Int)(z: Int) = x + y + z
val sumFunction: Int => Int => Int => Int = sum
Run Code Online (Sandbox Code Playgroud)

这也是同样的原因

def sum(x: Int, y: Int) = x + y
List(1,2,3).reduce(sum)
Run Code Online (Sandbox Code Playgroud)

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

以下是关于 scala 何时执行 eta 扩展的更深入讨论:/sf/answers/167584441/


关于选择采用哪个,我将向您指出这个答案,该答案非常详尽。