2013-06-24 31 views
5

Sau đây là một phiên bản đơn giản của vấn đề thực sự của tôi:Scala: lỗi trong tham số ngầm

class Z[T] 
object E extends Enumeration { 
    implicit val z = new Z[Value] 
    val X, Y = Value 
} 
implicit def f[T : Z] = (getter: T) => 0 
implicit def o[T](v: Option[T])(implicit toInt: T => Int) = 0 
def e: Option[E.Value] = null 
val b: Int = e 

này hoạt động, với b ngầm chuyển đổi sang o (e) (f (E.z)). Nhưng với những thay đổi nhỏ sau:

implicit def f[T : Z] = (setter: T => Unit) => 0 
implicit def o[T](v: Option[T])(implicit toInt: (T => Unit) => Int) = 0 

nó vẫn thất bại tìm E.z giá trị tiềm ẩn thích hợp mặc dù không có sự khác biệt cần thiết từ mã ban đầu, trong khi chuyển đổi rõ ràng bằng tay để o (e) (f (E.z)) vẫn hoạt động.

Tôi biết việc triển khai thông số ngầm chưa hoàn tất và vẫn còn nhiều vấn đề chưa được giải quyết. Nếu đây là một trong số họ, tôi muốn báo cáo cho những người đóng góp Scala. Vì vậy, câu hỏi của tôi là, a) đây thực sự là một lỗi? b) nếu vậy, ở đâu và làm thế nào tôi có thể nộp một lỗi để nó có thể được sửa trong tương lai?

CẬP NHẬT câu trả lời

Travis' làm việc như một nét duyên dáng! Bằng cách này, các mã trên là một cách giải quyết cho vấn đề ban đầu của tôi:

implicit object E extends Enumeration { val X, Y = Value } 
implicit object F extends Enumeration { val X, Y = Value } 
implicit def f[T <: Enumeration](getter: T#Value)(implicit e: T) = 0 
implicit def o[T](v: Option[T])(implicit toInt: T => Int) = 0 
val b: Int = Some[E.Value](null) 

Trong mã này, tình hình là cách khác xung quanh: nó hoạt động với phiên bản setter nhưng không phải với phiên bản getter đơn giản hơn. Trình biên dịch phàn nàn rằng nó gây nhầm lẫn cho dù sử dụng E hoặc F là tham số ngầm định mặc dù sử dụng F không thực sự biên dịch cũng không có ý nghĩa. Tôi quản lý để làm cho nó hoạt động bằng cách thực hiện một điều tương tự:

implicit def f[S <% T => T, T <: Enumeration](getter: T#Value)(implicit e: T) = 0 

Điều này hoạt động, và mặc dù tôi bằng cách nào đó có thể làm việc, tôi vẫn không hiểu được logic đằng sau ma thuật này.

+0

Thú vị. Chạy lệnh này với '-Xlog-implicits', có vẻ như' T' trong 'f [T: Z]' không được suy ra như 'E.Value'. Do đó điều này làm việc: 'val b: Int = o (e) (f [E.Value])' nhưng điều này không: 'val b: Int = o (e) (f)'. – gourlaysama

Trả lời

6

Bạn đã chạy vào một biến thể khác của this limitation trong hệ thống suy luận kiểu của Scala.

Trình biên dịch sẽ giải quyết T cho f nếu trong trường hợp đầu tiên, nơi mà nó đang tìm kiếm một chuyển đổi ngầm từ đồng bằng cũ E.Value-Int, nhưng không phải trong thứ hai, nơi mà nó muốn chuyển đổi từ E.Value => Unit (ví dụ, Function1[E.Value, Unit]) đến Int.

May mắn thay có một cách giải quyết dễ dàng trong trường hợp như thế này, chỉ cần sử dụng một cái nhìn bị ràng buộc:

implicit def f[F <% T => Unit, T: Z] = (setter: F) => 0 

này sẽ desugar một cái gì đó như sau:

implicit def f[F, T](implicit st: F <:< (T => Unit), ev: Z[T]) = (setter: F) => 0 

Bây giờ khi trình biên dịch muốn chuyển đổi từ E.Value => Unit đến Int nó sẽ có thể giải quyết F đến E.Value => Unit ngay lập tức và sau đó T đến E.Value.

+0

Cảm ơn câu trả lời, nó hoạt động như một sự quyến rũ! Nhưng tôi vẫn không hiểu làm thế nào ma thuật này hoạt động .. Bạn có thể nhìn vào bản cập nhật ở trên và đưa ra một lời giải thích? Có vẻ như S thậm chí không cần thiết phải làm cho tinh thần để có được hệ thống suy luận kiểu làm việc .. Bí ẩn. –

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