教程中的Scala currying示例让我很困惑

时间:2018-04-20 05:24:19

标签: scala

我正在阅读有关Scala currying here的一些内容,我不太了解这个例子:

def foldLeft[B](z: B)(op: (B, A) => B): B
  1. 方括号中的[B]是多少?为什么它在括号中?冒号后的B是返回类型吗?什么类型?
  2. 看起来这个方法有2个参数列表:一个参数名为z,另一个参数名为op,是一个函数。

    1. op看起来需要一个函数(B, A) => B)。右边是什么意思?它返回B
    2. 这显然是如何使用的:

      val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
      val res = numbers.foldLeft(0)((m, n) => m + n)
      print(res) // 55
      

      发生了什么事?调用时为什么不需要[B]?

3 个答案:

答案 0 :(得分:3)

在Scala文档中,A类型(有时是A1)通常是集合元素类型的占位符。所以,如果你有......

List('c','q','y').foldLeft( //....etc.

...然后A成为Char的引用,因为该列表是List[Char]

BfoldLeft必须处理的第二种类型的占位符。具体来说,它是第一个参数的类型以及foldLeft结果的类型。大多数情况下,当调用foldLeft时,您实际上不需要指定它,因为编译器会推断它。所以,是的,它可能是......

numbers.foldLeft[Int](0)((m, n) => m + n)

...但为什么要这么麻烦?编译器知道它是一个Int,读取它的人也是如此(任何知道Scala的人)。

(B, A) => B是一个函数,它接受2个参数,一个类型为B,另一个类型为A,并生成类型为B的结果。

答案 1 :(得分:2)

  

方括号中的[B]是什么?

一个类型参数(也称为"泛型"如果你以前见过像Java这样的东西)

  

为什么它在括号中?

因为类型参数是用括号括起来的,所以只是Scala语法。 Java,C#,Rust,C ++使用尖括号< >用于类似目的,但由于Scala中的数组被访问为arr(idx),并且(与Haskell或Python不同)Scala不使用[ ... ]列表推导,方括号可以用于类型参数,并且不需要尖括号(无论如何都难以解析,特别是在允许中缀和后缀运算符几乎任意名称的语言中)。

  

冒号之后的B是返回类型吗?

右。

  

什么类型?

同上。返回类型为B

  

看起来这个方法有2个参数列表:一个参数名为z,另一个参数名为op,是一个函数。

此方法具有类型参数B和值参数的两个参数列表,正确。这样做是为了简化类型推断:类型B可以从第一个参数z推断出来,所以在写下op的lambda表达式时不必重复它。如果zop位于相同的参数列表中,这将无效。

  

op看起来需要一个函数(B, A) => B

参数op的类型是(B, A) => B,即Function2[B, A, B],一个带BA并返回{的函数{1}}。

  

右侧是什么意思?它返回B

  

发生了什么事?

B充当累加器,m是列表的当前元素。折叠以整数值n开始,然后从左到右累积,将所有数字相加。您可以写0而不是(m, n) => m + n

  

为什么调用时不需要[_ + _]?

B的类型推断出来。在许多其他情况下,无法自动推断泛型类型,那么您必须通过将其作为方括号中的参数传递来明确指定返回类型。

答案 2 :(得分:0)

这就是所谓的多态性。该函数可以在多种类型上工作,有时您希望提供一个参数,说明将使用哪种类型。基本上B是一个类型参数,可以明确地作为一个类型给出,它应该是Int,然后它应该用方括号给出,或隐含在括号中,就像你使用0一样。阅读这里的多态性Scala polymorphism