我只是在看讲座 2.2 高阶函数(关于Scala 中的函数式编程原则)。在那里,一个 sum 函数定义如下:
def sum(f: Int => Int, a: Int, b: Int) { ... }
稍后,相同的函数定义如下:
def sum(f: Int => Int)(a: Int, b: Int) { ... }
它们似乎是等价的,但没有解释为什么要重新选择。
我只是在看讲座 2.2 高阶函数(关于Scala 中的函数式编程原则)。在那里,一个 sum 函数定义如下:
def sum(f: Int => Int, a: Int, b: Int) { ... }
稍后,相同的函数定义如下:
def sum(f: Int => Int)(a: Int, b: Int) { ... }
它们似乎是等价的,但没有解释为什么要重新选择。
第二个定义声明了一个带有两个参数列表的方法。忽略隐式,这通常用于启用柯里化函数应用程序。基本思想是你可以绑定一个函数的一些参数,这会产生另一个带有更少参数的函数,即那些尚未绑定的函数。这是一个简单的教科书示例:
def add(xs: List[Int])(y: Int) =
xs.map(_ + y)
// Bind first argument and store resulting function in f
val f = add(List(2,3,5,7,11))_
println(f(0)) // List(2, 3, 5, 7, 11)
println(f(10)) // List(12, 13, 15, 17, 21)
// Bind first argument and store resulting function in g
val g = add(List(0,1,0,1,0,1))_
println(g(1)) // List(1, 2, 1, 2, 1, 2)
println(g(-1)) // List(-1, 0, -1, 0, -1, 0)
// Regular invocation
println(add(List(1,2,3))(4)) // List(5, 6, 7)
你会在网上找到很多关于柯里化的文章,例如,如何在 Scala 中使用柯里化,或者在 Scala 中有多种柯里化方法。
关于为什么要重新选择一个:在 Haskell 中,您基本上总是会选择 curried 版本而不是 uncurried 版本,因为后者为您提供了能够部分绑定参数的优势,并且没有“语法惩罚”或运行时惩罚用于使用咖喱版本。由于这不适用于 Scala(正如您可以从上面的代码片段中观察到的语法那样),您可能希望更喜欢 uncurried 样式,除非您知道您的方法/函数的最可能用例会受益从咖喱。
有点,但不完全是。最大的不同在于,拥有多个参数列表可以让我们更轻松地使用该函数,而无需指定所有参数。
例如,让我们像这样定义两个函数:
def sum1(f: Int => Int, a: Int, b: Int) = f(a + b)
def sum2(f: Int => Int)(a: Int, b: Int) = f(a + b)
现在让我们定义一个函数,该函数g
将另一个函数作为参数,该函数接受两个Int
s 并产生一个Int
def g(f: (Int, Int) => Int) = f(3, 5)
带有多个参数列表的版本sum
允许我们只指定第一个列表的参数,然后将此部分应用的函数传递给g
:
g(sum2(_ + 1))
这是非常简单且非常干净的。
如果没有单独的参数列表,如 中sum1
,我们必须编写一个 lambda 表达式来显示a
和b
参数的来源:
g((a: Int, b: Int) => sum1(_ + 1, a, b))