Ответ 1
Метод fold
(первоначально добавленный для параллельного вычисления) менее мощный, чем foldLeft
в терминах типов, к которым он может быть применен. Его подпись:
def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1
Это означает, что тип, над которым выполняется свертывание, должен быть супертипом типа элемента коллекции.
def foldLeft[B](z: B)(op: (B, A) => B): B
Причина в том, что fold
может быть реализована параллельно, а foldLeft
не может. Это происходит не только из-за части *Left
, которая подразумевает, что foldLeft
идет слева направо последовательно, но также и потому, что оператор op
не может комбинировать результаты, вычисляемые параллельно - он определяет только, как объединить тип агрегации B
с типом элемента A
, но не как объединить две агрегации типа B
. Метод fold
, в свою очередь, определяет это, потому что тип агрегации A1
должен быть супертипом типа элемента A
, то есть A1 >: A
. Это отношение супертипа позволяет одновременно сгибать агрегацию и элементы и комбинировать агрегаты - как с одним оператором.
Но это отношение супертипа между агрегацией и типом элемента также означает, что тип агрегации A1
в вашем примере должен быть супертипом (ArrayBuffer[Int], Int)
. Поскольку нулевой элемент вашего агрегации ArrayBuffer(1, 2, 4, 5)
типа ArrayBuffer[Int]
, тип агрегации определяется как супертип обоих из них - и это Serializable with Equals
, единственная наименее верхняя граница кортежа и массива буфер.
В общем случае, если вы хотите разрешить параллельное свертывание для произвольных типов (что делается не по порядку), вы должны использовать метод aggregate
, который требует определения того, как объединяются две совокупности. В вашем случае:
r.aggregate(ArrayBuffer(1, 2, 4, 5))({ (x, y) => x -- y._1 }, (x, y) => x intersect y)
Btw, попробуйте написать свой пример с помощью reduce
/reduceLeft
- из-за отношений супертипа между типом элемента и типом агрегации, которые оба эти методы имеют, вы обнаружите, что это приводит к аналогичной ошибке, который вы описали.