2013-04-19 26 views
32

Tôi đang cố gắng hiểu gấp nếp gấp và công việc giảm và giảm tương ứng. Tôi đã từng lần và foldLeft như ví dụ của tôiScala: fold vs foldLeft

scala> val r = List((ArrayBuffer(1, 2, 3, 4),10)) 
scala> r.foldLeft(ArrayBuffer(1,2,4,5))((x,y) => x -- y._1) 

scala> res28: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(5) 

scala> r.fold(ArrayBuffer(1,2,4,5))((x,y) => x -- y._1) 
<console>:11: error: value _1 is not a member of Serializable with Equals 
       r.fold(ArrayBuffer(1,2,4,5))((x,y) => x -- y._1) 

Tại sao fold đã không làm việc như foldLeft? Serializable with Equals là gì? Tôi hiểu fold và foldLeft có chữ ký API khác nhau nhỏ về các kiểu generic chung. Xin cho biết. Cảm ơn.

+3

Bản sao có thể có của [Sự khác biệt giữa nếp gấp và nếp gấpLeft hoặc foldRight?] (Http://stackoverflow.com/q/6253978) –

+0

Phiên bản scala là gì? –

+0

Phiên bản scala của tôi là 2.10.1 – thlim

Trả lời

54

Phương thức fold (ban đầu được thêm để tính toán song song) ít mạnh hơn foldLeft về loại có thể áp dụng cho. Chữ ký của nó là:

def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 

Điều này có nghĩa là loại mà việc gấp được thực hiện phải là siêu loại của loại phần tử thu thập.

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

Lý do là fold có thể được triển khai song song, trong khi foldLeft không thể. Điều này không chỉ vì phần *Left ngụ ý rằng foldLeft đi từ trái sang phải tuần tự, mà còn bởi vì toán tử op không thể kết hợp các kết quả được tính song song - nó chỉ xác định cách kết hợp loại tổng hợp B với loại phần tử A, nhưng không phải cách kết hợp hai tập hợp loại B. Phương pháp fold, đến lượt nó, không xác định điều này, bởi vì kiểu tổng hợp A1 phải là siêu kiểu của loại phần tử A, đó là A1 >: A. Mối quan hệ siêu kiểu này cho phép trong cùng một thời gian gấp trên tổng hợp và các phần tử, và kết hợp các kết hợp - cả hai với một toán tử đơn.

Tuy nhiên, mối quan hệ siêu kiểu này giữa tập hợp và loại phần tử cũng có nghĩa là loại tổng hợp A1 trong ví dụ của bạn phải là siêu kiểu của (ArrayBuffer[Int], Int). Vì phần tử số 0 của tập hợp của bạn là ArrayBuffer(1, 2, 4, 5) thuộc loại ArrayBuffer[Int], loại tổng hợp được suy ra là siêu kiểu của cả hai loại này - và đó là Serializable with Equals, giới hạn trên ít nhất của bộ đệm và bộ đệm mảng.

Nói chung, nếu bạn muốn cho phép gấp song song cho các loại tùy ý (được thực hiện theo thứ tự), bạn phải sử dụng phương pháp aggregate yêu cầu xác định cách kết hợp hai tập hợp. Trong trường hợp của bạn:

r.aggregate(ArrayBuffer(1, 2, 4, 5))({ (x, y) => x -- y._1 }, (x, y) => x intersect y) 

Btw, hãy thử viết ví dụ của bạn với reduce/reduceLeft - vì mối quan hệ giữa siêu kiểu loại phần tử và các loại kết hợp cả hai phương pháp này có, bạn sẽ thấy rằng nó dẫn đến một lỗi tương tự như lỗi bạn đã mô tả.