2011-09-02 22 views
14

Nếu tôi tạo ra một cho sự hiểu biết với một định nghĩa giá trị với Option, nó hoạt động như mong đợi:Tại sao Scala chọn kiểu 'sản phẩm' cho 'cho' biểu thức liên quan đến Hoặc và định nghĩa giá trị

scala> for (a <- Some(4); b <- Some(5); val p = a * b) yield p 
res0: Option[Int] = Some(20) 

Làm tương tự điều với Hoặc hoạt động nếu tôi không có định nghĩa giá trị:

scala> for (a <- Right(4).right; b <- Right(5).right) yield a * b 
res1: Either[Nothing,Int] = Right(20) 

Nhưng nếu tôi sử dụng định nghĩa giá trị, scala dường như để suy ra các loại thùng chứa sai cho cho sự hiểu biết:

scala> for (a <- Right(4).right; b <- Right(5).right; val p = a * b) yield p 
<console>:8: error: value map is not a member of Product with Serializable with Either[Nothing,(Int, Int)] 
for (a <- Right(4).right; b <- Right(5).right; val p = a * b) yield p 
          ^

Tại sao lại thực hiện việc này? Những cách xung quanh hành vi này có sẵn?

Trả lời

19

Những vấn đề xuất phát từ val p = a*b Nếu bạn viết đơn giản

cho (a < - (4) .right Ngay; b < - Phải (5) .right) mang a * b

nó biên dịch và bạn nhận được kết quả phù hợp.

Vấn đề của bạn có hai nguyên nhân

Thứ nhất, Either dự mapflatMap không có chữ ký thông thường, cụ thể là cho bản đồ thói quen và flatMap định nghĩa trong một lớp generic M[A], (A => B) => M[B](A => M[B]) => M[B]. Các M[A] các thói quen được định nghĩa là Either[A,B].RightProjection, nhưng trong kết quả và đối số, chúng tôi có Either[A,B] và không phải là chiếu.

Thứ hai, cách thức val p = a*b trong bản dịch hiểu được dịch. Scala tham khảo, 6.19 p 90:

Một máy phát điện p < - e theo sau là một giá trị định nghĩa p '= e' là dịch sang các máy phát điện sau đây của cặp giá trị, trong đó x và x 'là những cái tên mới mẻ :

(p,p′) <- for([email protected]<-e) yield {val x′@p′ = e′; (x,x′)} 

Hãy đơn giản hóa mã chỉ là một chút, thả a <-. Ngoài ra, bp được đổi tên thành ppp để gần hơn với quy tắc ghi lại, với pp cho p'. a phải nằm trong phạm vi cho (p < - sản lượng phải (5) .right; val pp = a * p) pp

theo quy tắc, chúng tôi phải thay thế định nghĩa của trình tạo +. Xung quanh đó, for()yield pp, không thay đổi.

for((p, pp) <- for([email protected] <- Right(5).right) yield{val [email protected] = a*p; (x,xx)}) yield pp 

Các bên cho được viết lại với một bản đồ đơn giản

for((p, pp) <- Right(5).right.map{case [email protected] => val [email protected] = a*p; (x,xx)}) yield pp 

Dưới đây là vấn đề. Right(5).right.map(...) thuộc loại Either[Nothing, (Int,Int)], không phải Either.RightProjection[Nothing, (Int,Int)] như chúng tôi muốn. Nó không hoạt động ở bên ngoài (cũng chuyển đổi thành map.Không có phương pháp map trên Either, chỉ được xác định trên các phép chiếu.

Nếu bạn xem xét kỹ thông báo lỗi của mình, ngay cả khi nó đề cập đến ProductSerializable, nó nói rằng đó là Either[Nothing, (Int, Int)] và không có bản đồ nào được xác định trên đó. Cặp (Int, Int) xuất phát trực tiếp từ quy tắc viết lại.

Việc đọc hiểu được thiết kế để hoạt động tốt khi tôn trọng chữ ký thích hợp. Với thủ thuật với dự án Either (cũng có những ưu điểm của nó), chúng tôi gặp phải vấn đề này.

+1

Ah, điều đó bắt đầu có ý nghĩa. Bạn có một vài lỗi đánh lừa tôi lúc đầu (thiếu số nguyên tố, lỗi loại tinh tế, vv) mà tôi sẽ làm sạch ngay. – srparish

+0

Kết quả thú vị ở trên là nếu tôi có loại monadic nhất quán, tôi sẽ ổn thôi. Vì vậy, nếu tôi chỉ quan tâm đến các dự đoán đúng, tôi có thể tạo ra một tiềm ẩn như sau đây thực sự khắc phục được vấn đề: deficit def RightProjection [A, B] (v: Hoặc [A, B]): Either.RightProjection [A, B] = v.right – srparish

+1

Một lần nữa, cảm ơn rất lớn vì đã đăng ký toàn diện! Tôi đã đọc tài liệu tham khảo và vẫn chưa tìm ra chuyện gì đang diễn ra. Rõ ràng trong ví dụ đơn giản này, một * b có thể được chuyển đến sản lượng, nhưng nếu được thay thế bằng một phép tính phức tạp cần được chuyển đến hàm trả về một giá trị khác (lặp lại vài lần này), có thể sử dụng trung gian giá trị chuyển nhượng có thể được sạch hơn nhiều tìm kiếm sau đó phải có nhiều cấp độ của xích cho/báo cáo sản lượng. – srparish

Các vấn đề liên quan