0

我只是在看讲座 2.2 高阶函数(关于Scala 中的函数式编程原则)。在那里,一个 sum 函数定义如下:

def sum(f: Int => Int, a: Int, b: Int) { ... }

稍后,相同的函数定义如下:

def sum(f: Int => Int)(a: Int, b: Int) { ... }

它们似乎是等价的,但没有解释为什么要重新选择。

4

2 回答 2

2

第二个定义声明了一个带有两个参数列表的方法。忽略隐式,这通常用于启用柯里化函数应用程序。基本思想是你可以绑定一个函数的一些参数,这会产生另一个带有更少参数的函数,即那些尚未绑定的函数。这是一个简单的教科书示例:

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 样式,除非您知道您的方法/函数的最可能用例会受益从咖喱

于 2012-09-27T08:07:24.297 回答
1

有点,但不完全是。最大的不同在于,拥有多个参数列表可以让我们更轻松地使用该函数,而无需指定所有参数。

例如,让我们像这样定义两个函数:

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将另一个函数作为参数,该函数接受两个Ints 并产生一个Int

def g(f: (Int, Int) => Int) = f(3, 5)

带有多个参数列表的版本sum允许我们只指定第一个列表的参数,然后将此部分应用的函数传递给g

g(sum2(_ + 1))

这是非常简单且非常干净的。

如果没有单独的参数列表,如 中sum1,我们必须编写一个 lambda 表达式来显示ab参数的来源:

g((a: Int, b: Int) => sum1(_ + 1, a, b))
于 2012-09-27T08:07:51.300 回答