为什么这个函数参数需要在元组上加双括号?
Why does this function parameter need double braces on a tuple?
注意:我正在使用 scalac。请不要推荐使用 sbt 代替。
我 运行 遇到了一个我可以解决的特殊问题,但我想知道为什么它会那样工作,而不是我以前那样工作。这是一个代码片段:
def multiply[A](r1: Vector[A], r2: Vector[A], multOp: (A,A) => A, sumOp: (A, A) => A) =
r1.zip(r2).map(multOp).reduce(sumOp)
它不编译,导致错误消息如下:
Error:(73, 20) type mismatch;
found : (A, A) => A
required: ((A, A)) => ?
r1.zip(r2).map(multOp).reduce(sumOp)
将代码段更改为:
def multiply[A](r1: Vector[A], r2: Vector[A], multOp: ((A,A)) => A, sumOp: (A, A) => A) =
r1.zip(r2).map(multOp).reduce(sumOp)
将解决问题。
请注意,sumOp
只适用于一对牙套。
为什么?
方法map
定义为采用单个参数,而(A, A) => A
有两个。通过将两个类型A的参数转换为一个类型为(A,A)的元组参数,它编译。
(A, A) => A // fails due to two params of type A
((A, A)) => A // works due to one param of type (A, A)
另一方面,reduce
被定义为采用相同类型的两个参数,因此很高兴采用符合该描述的 sumOp
。
以下是分别在 TraversableLike
和 TraversableOnce
中找到的完整签名:
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
def reduce[A1 >: A](op: (A1, A1) => A1): A1
编辑(额外信息):
原因是 reduce
总是采用 2 元函数(即两个参数的函数),以便通过迭代将 collection 减少为单个值将该函数应用于上一个应用程序的结果和下一个值。另一方面,map
始终采用 1-arity 函数,并将基础值映射到该函数。在 Option
、Future
等的情况下,只有一个基础值,而在 Vector
的情况下(像你的)可能有很多,所以它适用于每个元素collection.
在某些库中,您可能会遇到带有 two-parameter 函数的 map2
。例如,为了组合两个选项(实际上,任何应用函子,但让我们把理论放在一边),你可以这样做:
// presudocode
Option(1, 2).map2((a, b) => a + b)
这会给你一个 Option(3)
。我认为这种机制已经被放弃,取而代之的是更容易理解的 map + product
// presudocode
(Option(1) product Option(2)) map ((a, b) => a + b)
上面一行的实际 scalaz 语法是(在 Scalaz 7 中):
(Option(1) |@| Option(2))((a, b) => a + b)
它们是同样强大的原则(一个可以做什么,另一个可以做什么,不多也不少)所以后一个通常是首选,有时它是唯一提供的,但是是的,你可能时不时遇到map2
好的,这是一些额外的信息。就 map
而言,请记住始终只有一个参数传入和一个值输出。
如果您将第一个代码段定义为:
def multiply[A](r1: Vector[A], r2: Vector[A], multOp: (A,A) => A, sumOp: (A, A) => A) =
(r1, r2).zipped.map(multOp).reduce(sumOp)
zipped
元组的 map
方法采用带有两个参数的函数 (A, A) => B
,因为这是预期的使用模式。
这种方法还避免了创建中间层 Vector[(A, A)]
。
注意:我正在使用 scalac。请不要推荐使用 sbt 代替。
我 运行 遇到了一个我可以解决的特殊问题,但我想知道为什么它会那样工作,而不是我以前那样工作。这是一个代码片段:
def multiply[A](r1: Vector[A], r2: Vector[A], multOp: (A,A) => A, sumOp: (A, A) => A) =
r1.zip(r2).map(multOp).reduce(sumOp)
它不编译,导致错误消息如下:
Error:(73, 20) type mismatch;
found : (A, A) => A
required: ((A, A)) => ?
r1.zip(r2).map(multOp).reduce(sumOp)
将代码段更改为:
def multiply[A](r1: Vector[A], r2: Vector[A], multOp: ((A,A)) => A, sumOp: (A, A) => A) =
r1.zip(r2).map(multOp).reduce(sumOp)
将解决问题。
请注意,sumOp
只适用于一对牙套。
为什么?
方法map
定义为采用单个参数,而(A, A) => A
有两个。通过将两个类型A的参数转换为一个类型为(A,A)的元组参数,它编译。
(A, A) => A // fails due to two params of type A
((A, A)) => A // works due to one param of type (A, A)
另一方面,reduce
被定义为采用相同类型的两个参数,因此很高兴采用符合该描述的 sumOp
。
以下是分别在 TraversableLike
和 TraversableOnce
中找到的完整签名:
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
def reduce[A1 >: A](op: (A1, A1) => A1): A1
编辑(额外信息):
原因是 reduce
总是采用 2 元函数(即两个参数的函数),以便通过迭代将 collection 减少为单个值将该函数应用于上一个应用程序的结果和下一个值。另一方面,map
始终采用 1-arity 函数,并将基础值映射到该函数。在 Option
、Future
等的情况下,只有一个基础值,而在 Vector
的情况下(像你的)可能有很多,所以它适用于每个元素collection.
在某些库中,您可能会遇到带有 two-parameter 函数的 map2
。例如,为了组合两个选项(实际上,任何应用函子,但让我们把理论放在一边),你可以这样做:
// presudocode
Option(1, 2).map2((a, b) => a + b)
这会给你一个 Option(3)
。我认为这种机制已经被放弃,取而代之的是更容易理解的 map + product
// presudocode
(Option(1) product Option(2)) map ((a, b) => a + b)
上面一行的实际 scalaz 语法是(在 Scalaz 7 中):
(Option(1) |@| Option(2))((a, b) => a + b)
它们是同样强大的原则(一个可以做什么,另一个可以做什么,不多也不少)所以后一个通常是首选,有时它是唯一提供的,但是是的,你可能时不时遇到map2
好的,这是一些额外的信息。就 map
而言,请记住始终只有一个参数传入和一个值输出。
如果您将第一个代码段定义为:
def multiply[A](r1: Vector[A], r2: Vector[A], multOp: (A,A) => A, sumOp: (A, A) => A) =
(r1, r2).zipped.map(multOp).reduce(sumOp)
zipped
元组的 map
方法采用带有两个参数的函数 (A, A) => B
,因为这是预期的使用模式。
这种方法还避免了创建中间层 Vector[(A, A)]
。