我正在观看讲座2.2高阶函数(Functional programming principles in Scala)。在那里,sum函数定义如下:
def sum(f: Int => Int, a: Int, b: Int) { ... }
稍后,同样的函数定义如下:
def sum(f: Int => Int)(a: Int, b: Int) { ... }
它们似乎是等价的,但没有解释为什么选择过来。
答案 0 :(得分:2)
第二个定义声明了一个带有两个参数列表的方法。忽略implicits,这通常用于启用curried函数应用程序。基本思想是你可以绑定一个函数的一些参数,这会产生另一个带有较少参数的函数,即那些尚未绑定的函数。这是一个简单的教科书示例:
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)
你会发现很多关于在线currying的文章,例如,如何使用currying in Scala,或者有multiple ways to curry in Scala。
关于为什么要选择一个以上:在Haskell中你基本上总是会选择curried版本而不是未经考虑的版本,因为后者给你的优点是能够部分绑定参数,并且因为没有“语法惩罚”或使用curried版本的运行时惩罚。由于Scala不是这样(正如您在上面的代码片段中可以看到的那样),您可能希望更喜欢未经处理的样式,除非您知道方法/函数的最可能用例{ {3}}
答案 1 :(得分: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
,它将另一个函数作为参数,该函数需要两个Int
并生成一个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))