3

我对这个 Scala 表示法有点困惑:

List(1, 2, 3).foldLeft(0)((x, acc) => acc+x)

“0”和函数都是 foldLeft 的参数,为什么它们在两个相邻的括号组中传递?我会考虑这个工作:

List(1, 2, 3).foldLeft(0, ((x, acc) => acc+x))

但事实并非如此。谁能给我解释一下?另外,如何以及为什么要声明这种类型的函数?谢谢

4

3 回答 3

7

Scala 允许您拥有多个参数列表:

def foo(a: Int)(b: String) = ???
def bar(a: Int)(b: String)(c: Long) = ???

foldLeft 使用这种语法的原因是编译器进行类型推断的方式:已经推断出前一组参数中的类型,用于推断连续参数组中的类型。在 foldLeft 的情况下,它允许您将类型归属放在 旁边(x, acc),因此而不是:

List(1, 2, 3).foldLeft(0)((x: Int, acc: Int) => acc+x)

你可以只写

List(1, 2, 3).foldLeft(0)((x, acc) => acc+x)
于 2013-11-07T15:13:38.333 回答
3

这是Scala中多个参数列表的示例。它们实际上只是普通方法调用的语法糖(如果您查看类文件的方法签名,javap您会发现当编译为 Java 字节码时,它们都组合成一个参数列表)。支持多个参数列表的原因有两个:

  1. 将函数作为参数传递:Scala 将允许您将带有单个参数的参数列表替换为花括号中的函数文字{}。例如,您的代码可以重写为List(1, 2, 3).foldLeft(0) { (x, acc) => acc+x },这可能被认为更具可读性。(再说一次,我只是List(1, 2, 3).foldLeft(0)(_+_)在这种情况下使用......)能够使用这样的花括号使用户可以声明看起来更像本机语法的新函数。Actorsreact函数就是一个很好的例子。
  2. 类型推断:类型推断过程中有一些细节(我承认我并不完全理解),这使得根据前面列表中的类型推断后面列表中使用的类型变得更加容易。例如,z传递给的初始值foldLeft用于推断函数参数的结果类型(和左参数类型)。
于 2013-11-07T15:23:12.677 回答
2

因为在 Scala 中,您可以在多个组中定义函数参数()

def test(a: String)(b: String)(implicit ev: Something) { }

最实际的情况是需要上下文绑定或柯里化,例如implicit范围内可用的特定定义。

例如,Future将期望一个implicit executor. 看这里

如果您查看该foldLeft方法的定义,您会看到第一个参数是一个累加器,第二个参数是用于柯里化的函数。

def foldLeft[B](z: B)(op: (B, A) ⇒ B): B

括号是一个非常有用的关注点分离。此外,一旦您定义了一个方法:

    def test(a: String)(b: String)
You can't call it with: test("a", "b");
于 2013-11-07T15:13:38.733 回答