2012-11-22 18 views
13

Say chúng tôi có hai đặc điểm sau đây:Scala xem ứng dụng puzzler

trait Foo[A] { def howMany(xs: List[A]) = xs.size } 
trait Bar 

Và một chuyển đổi ngầm từ thứ hai đến thứ nhất:

implicit def bar2foo[A](bar: Bar) = new Foo[A] {} 

Chúng tôi tạo ra một Bar và một danh sách các số nguyên:

val bar = new Bar {} 
val stuff = List(1, 2, 3) 

Bây giờ tôi hy vọng những điều sau đây sẽ hoạt động:

bar howMany stuff 

Nhưng nó không:

scala> bar howMany stuff 
<console>:13: error: type mismatch; 
found : List[Int] 
required: List[A] 
       bar howMany stuff 
         ^

Vì vậy, chúng tôi đi đến the spec, trong đó có điều này để nói (nhấn mạnh in đậm là của tôi):

Lần được áp dụng trong ba tình huống .

  1. [Không phải là liên quan ở đây.]

  2. Trong một lựa chọn em với e loại T, nếu chọn m không biểu thị một thành viên của T. Trong trường hợp này, chế độ xem v được tìm kiếm trong đó được áp dụng cho e và kết quả có chứa thành viên có tên m. Số tiền tìm kiếm được tiến hành như trong trường hợp các tham số ngầm định, trong đó phạm vi tiềm ẩn là một trong số T. Nếu tìm thấy một chế độ xem như vậy, lựa chọn e.m được chuyển đổi thành v (e) .m.

  3. Trong một lựa chọn em (args) với e loại T, nếu chọn m biểu thị một số thành viên (s) của T, nhưng không ai trong số những thành viên được áp dụng cho đối số args. Trong trường hợp này một cái nhìn v được tìm kiếm đó là áp dụng đối với e và có kết quả chứa một phương thức m đó là áp dụng đối với args. Tìm kiếm tiếp tục như trong trường hợp của thông số tiềm ẩn, trong đó phạm vi tiềm ẩn là một trong số T. Nếu một chế độ xem như vậy được tìm thấy, lựa chọn e.m được chuyển đổi thành v (e) .m (args).

Vì vậy, chúng tôi cố gắng sau, suy nghĩ nó phải là quá vô lý làm việc:

trait Foo[A] { def howMany(xs: List[A]) = xs.size } 
trait Bar { def howMany = throw new Exception("I don't do anything!") } 

implicit def bar2foo[A](bar: Bar) = new Foo[A] {} 

val bar = new Bar {} 
val stuff = List(1, 2, 3) 

Nhưng nó (trên cả hai 2.9.2 và 2.10.0-RC2, ít nhất) :

scala> bar howMany stuff 
res0: Int = 3 

Điều này dẫn đến một số hành vi thực sự kỳ lạ, như ví dụ trong this workaround cho this problem.

Tôi có ba câu hỏi (liên quan chặt chẽ):

  1. Có cách nào đơn giản (ví dụ, một trong những điều đó không liên quan đến việc thêm các phương pháp giả mạo với tên thích hợp) có quan điểm áp dụng một cách chính xác trong bản gốc trường hợp trên?
  2. Ai đó có thể cung cấp thông tin chi tiết về hành vi này không?
  3. Giả sử đây là hành vi dự định, nó có ý nghĩa gì không?

Tôi cũng đánh giá cao bất kỳ liên kết nào đến các cuộc thảo luận trước đây về vấn đề này — Tôi đã không có nhiều may mắn với Google.

Trả lời

1

Để tham khảo của mọi người, điều này chỉ có thể là một lỗi. Cách bạn biết đó là thông báo lỗi:

<console>:13: error: type mismatch; 
found : List[Int] 
required: List[A] 

Danh sách [A] không phải là loại thực - là Danh sách được áp dụng cho thông số loại của riêng nó. Đó không phải là một loại có thể được yêu cầu vì nó không phải là một loại có thể được thể hiện.

[Chỉnh sửa - còn quá sớm, ai biết tôi đang nói gì. Bỏ qua phần trên nhưng bạn vẫn có thể theo liên kết.]

Vé liên quan cho điều này là https://issues.scala-lang.org/browse/SI-6472.

0

Thay Foo của bạn với điều này:

trait Foo[_] { def howMany(xs: List[_]) = xs.size }

Nó hoạt động, mà còn làm cho tinh thần khá hơn rất nhiều với tôi bởi vì bạn Absolutly không quan tâm đến A.

+0

Điều đó làm việc trong trường hợp được đơn giản hóa cụ thể đó, nhưng nói chung tôi quan tâm đến 'A' — trong giải pháp cho vấn đề Scalaz được liên kết trong câu hỏi, ví dụ. –

0

chuyển đổi ngầm của bạn có vẻ là làm chính xác những gì bạn đã nói với nó.

implicit def bar2foo[A](bar: Bar) = new Foo[A] {} 

Chuyển đổi thanh thành đối tượng Foo[A] mới. Vì vậy, lần lượt

scala> bar howMany stuff 
<console>:13: error: type mismatch; 
found : List[Int] 
required: List[A] 
       bar howMany stuff 

Nó tìm loại 'A'.

Để làm công việc này theo cách bạn muốn nó (tôi nghĩ), thay vì xác định chế độ xem trên đặc điểm, bạn có thể thực hiện nó trên hàm.

trait Foo { def howMany[A](xs: List[A]) = xs.size } 
trait Bar 
implicit def bar2foo[A](bar: Bar) = new Foo{} 
val bar = new Bar {} 
val stuff = List(1, 2, 3) 

thì nó sẽ cho bạn kết quả mong muốn.

scala> bar howMany stuff 
res0: Int = 3 

hoặc bạn có thể xác định xem trên chức năng tiềm ẩn

trait Foo[A] { def howMany(xs: List[A]) = xs.size } 
trait Bar 

implicit def bar2foo[A](bar: Bar) = new Foo[Int] {} 

val bar = new Bar {} 
val stuff = List(1, 2, 3) 

Cá nhân tôi nghĩ rằng việc xác định nó trên chức năng là sạch hơn.

+0

Điều tôi muốn là hành vi "hiển nhiên" - tức là, đối với tham số 'A'' Foo' được suy ra dựa trên (các) đối số đến 'howMany'. Điều này rõ ràng là có thể, vì tôi có thể làm cho nó xảy ra bằng cách thêm phương thức 'howMany' giả mạo (hoàn toàn tùy ý) vào' Bar'. –

1

Điều này có vẻ giống như một lỗi nên câu trả lời của tôi là:

  1. tìm kiếm cho một lỗi simliar báo cáo so với trình biên dịch Scala và nếu không tìm thấy, báo cáo một lỗi mới https://issues.scala-lang.org/
  2. rằng một phần của spec doesn' t dường như quan trọng trong trường hợp này vì nó không nói về suy luận kiểu
  3. không thực hiện bất kỳ ý nghĩa với tôi

PS. Trong 2.8.1 cách giải quyết thêm phương thức giả của bạn vào Bar không làm cho nó biên dịch.

0

này, trong khi xấu xí, dường như làm việc:

(bar: Foo[Int]) howMany stuff 
Các vấn đề liên quan