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)
无需_.
现在的问题是:为什么需要多参数列表版本_才能启动柯里化?为什么这两个版本的语义在所有上下文中都不相同?
另外,后一个版本是否会受到某种阻碍?它有任何警告吗?
这两种语义不同的原因是方法和函数不是同一件事。
方法是成熟的 JVM 方法,而函数是值(即诸如Function1、Function2等类的实例)。
所以
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/
关于选择采用哪个,我将向您指出这个答案,该答案非常详尽。