它们的语义略有不同,但它们的用例大多相同,无论是在实际应用中还是在代码中的外观。
柯里化
在数学意义上在 Scala 中对函数进行柯里化非常简单:
val function = (x: Int, y: Int, z: Int) => 0
// function: (Int, Int, Int) => Int = <function3>
function.curried
// res0: Int => (Int => (Int => Int)) = <function1>
函数和方法
您似乎对以下事实感到困惑:在 Scala 中,(=>)函数 与 (def)方法 不同。方法不是一流的对象,而函数是(即它有curried 和tupled 方法,而Function1 更优秀)。
但是,可以通过称为 eta 扩展的操作将方法提升为函数。有关详细信息,请参阅this SO answer。您可以通过编写methodName _ 手动触发它,或者如果您在期望函数类型的位置提供方法,它将隐式完成。
def sumAndAdd4(i: Int, j: Int) = i + j + 4
// sumAndAdd4.curried // <- won't compile
val asFunction = sumAndAdd4 _ // trigger eta expansion
// asFunction: (Int, Int) => Int = <function2>
val asFunction2: (Int, Int) => Int = sumAndAdd4
// asFunction2: (Int, Int) => Int = <function2>
val asFunction3 = sumAndAdd4: (Int, Int) => Int
// asFunction3: (Int, Int) => Int = <function2>
asFunction.curried
// res0: Int => (Int => Int) = <function1>
asFunction2.curried
// res1: Int => (Int => Int) = <function1>
asFunction3.curried
// res2: Int => (Int => Int) = <function1>
{sumAndAdd4 _}.tupled // you can do it inline too
// res3: Int => (Int => Int) = <function1>
多参数列表的Eta扩展
如您所料,eta 扩展将每个参数列表提升为自己的函数
def singleArgumentList(x: Int, y: Int) = x + y
def twoArgumentLists(x: Int)(y: Int) = x + y
singleArgumentList _ // (Int, Int) => Int
twoArgumentLists _ // Int => (Int => Int) - curried!
val testSubject = List(1, 2, 3)
testSubject.reduce(singleArgumentList) // Int (6)
testSubject.map(twoArgumentLists) // List[Int => Int]
// testSubject.map(singleArgumentList) // does not compile, map needs Int => A
// testSubject.reduce(twoArgumentLists) // does not compile, reduce needs (Int, Int) => Int
但这并不是数学意义上的柯里化:
def hmm(i: Int, j: Int)(s: String, t: String) = s"$i, $j; $s - $t"
{hmm _} // (Int, Int) => (String, String) => String
这里,我们得到一个有两个参数的函数,返回另一个有两个参数的函数。
而且只指定它的一些参数并不是那么简单
val function = hmm(5, 6) _ // <- still need that underscore!
与函数一样,你可以毫不费力地得到一个函数:
val alreadyFunction = (i: Int, j: Int) => (k: Int) => i + j + k
val f = alreadyFunction(4, 5) // Int => Int
按照你喜欢的方式去做 - Scala 对很多事情都持不以为然的态度。我个人更喜欢多个参数列表,因为我经常需要部分应用一个函数,然后将它传递给某个地方,剩余参数将在该处给出,所以我不需要显式地进行 eta 扩展,并且我可以在方法定义站点享受更简洁的语法。