2

我有以下 Scala 代码示例,我想知道为什么我在 foldLeft 上出现错误,但在 foldRight 上却没有?

val xs = List(1,2,3) 
val ys = List(4,5,6)
(xs foldLeft ys) (_::_) // Error: Value :: is not a member of Int
(xs foldRight ys) (_::_) // Res: List(1, 2, 3, 4, 5, 6)

我是 Scala 的新手,所以请尽可能简单地回复。谢谢

4

3 回答 3

4

传递给foldLeft和的运算符(函数)的参数foldRight顺序相反。

所以在foldLeft_ :: _开始时ys :: xs.head,这没有任何意义。

有了foldRight,最里面的操作是xs.last :: ys,这很好。

参数顺序在运算符版本中更有意义:向右z /: ws推动(ie ),而向左推动(ie )。并且内部参数的顺序与上面vs.的顺序一致。zwsfoldLeftws :\ zzfoldRightzw

于 2015-07-06T21:29:14.643 回答
3

foldLeft 和 foldRight 有不同的签名,它们接受不同的参数

def foldLeft[B](z: B)(op: (B, A) => B): B
def foldRight[B](z: B)(op: (A, B) => B): B

查看op这两个函数的类型。对于 foldLeft,left 参数是您要折叠的集合的类型(在您的情况下是 int),而对于 foldRight,它是结果类型(在您的情况下是集合)。

因此,如果您希望将每个后续元素附加到结果列表中,您希望在 foldLeft 中使用不同的函数。

于 2015-07-06T21:29:42.563 回答
2

简而言之,操作 '::' 在 Int 上不可用,仅在集合上可用。如果你在 Scala REPL 中执行'(xs foldLeft ys) _',你会看到它产生了一个函数

((List[Int], Int) => List[Int]) => List[Int] = <function1>

所以第一个操作数是 List[Int],第二个是 Int。请注意,任何以 ':' 结尾的运算符都是特殊的,因为它使用左侧作为参数对右侧操作数进行操作。这称为“右关联”,而默认值通常是“左关联”。

因此 'aList :: anInt' 被翻译成 'anInt.::(aList)' 并且这会导致问题,因为 Int 没有 '::' 方法。

在“foldLeft”的情况下,您需要一个左关联函数来添加像“:+”这样的单个元素。所以这然后工作:

(xs foldLeft ys)(_ :+ _)

请注意,结果与 foldRight 完全不同,因此请务必根据您的情况选择更正一个。

于 2015-07-07T08:58:58.533 回答