使用以下语法定义启用了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?为什么这两个版本的语义在所有上下文中都是等价的呢?
此外,后一版本是否有些气馁?是否有任何警告?
答案 0 :(得分: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)
有效,即我们传递的方法明确要求函数。
以下是对scala执行eta扩展的更深入的讨论:https://stackoverflow.com/a/2394063/846273
关于选择采用哪种方法,我会指出this answer,这是非常详尽的。