2010-09-28 18 views
9

Xét đoạn mã sau:độ phân giải thông số ngầm với nhiều loại kinded cao

object foo { 

    trait Bar[Q[_]] 

    implicit object OptionBar extends Bar[Option] 

    def test[T, C[_]](c: C[T])(implicit bar: Bar[C]) =() 

    def main(args: Array[String]) { 
     test(Some(42): Option[Int]) //??? 
    } 
} 

này hoạt động, nhưng tôi cần phải gõ một số (42) theo Option [Int], nếu không đối tượng OptionBar ngầm sẽ không được đã giải quyết (vì một thanh [Some] được mong đợi thay thế). Có cách nào để tránh việc gõ rõ ràng, để tôi có được đối tượng OptionBar tiềm ẩn trong thử nghiệm ngay cả khi tôi thử nghiệm nguồn cấp dữ liệu với một số hoặc không?

[Làm rõ]

  • tôi đã sử dụng lựa chọn ở đây cũng giống như ví dụ, nó cũng nên làm việc nếu tôi có một Bar cho một lớp trừu tượng, vv
  • Giải pháp này cũng nên làm việc khi khác, không liên quan Bars là trong phạm vi, nói implicit object listBar extends Bar[list]

[cập nhật]

dường như làm contravariant tham số Bar làm t anh ta lừa:

object foo { 

    trait Bar[-Q[_]] //<--------------- 

    implicit object OptionBar extends Bar[Option] 
    implicit object ListBar extends Bar[List] 

    def test[T, C[_]](c: C[T])(implicit bar: Bar[C]) =() 

    def main(args:Array[String]) { 
    test(Some(42)) 
    } 
} 

Nhưng tất nhiên đây là một hạn chế nghiêm trọng về khả năng trong Bar, vì vậy tôi vẫn hy vọng có câu trả lời tốt hơn.

+1

Tại sao contravariance là một hạn chế nghiêm trọng? Không sử dụng nó, thì Bar là bất biến. Nếu bạn đang cố gắng sử dụng Bar như là một loại lớp chống lại các loại cao hơn mà contravariance dường như phù hợp trong tâm trí của tôi. Đó là tất nhiên cho đến khi bạn muốn điều trị các lớp con khác nhau. Tuy nhiên, trong trường hợp đó, bạn vẫn có các thủ thuật khác, như độ phân giải ngầm "ưu tiên" – jsuereth

+0

@Josh: Hãy xem xét một cái gì đó như 'trait Bar [Q [_]] {def zero [T]: Q [T]}', không trả lại None và Nil trong ví dụ của tôi. Nhưng tôi không thể có một phương pháp như vậy trong Bar, nếu tôi định nghĩa Q là contravariant. Khi bạn biết cách giải quyết điều này, hãy cho tôi biết ... – Landei

+1

Ngoài ra, đối với một loại kiểu tự nhiên contravariant, chẳng hạn như 'Equal [T]', tìm kiếm ngầm sẽ ưu tiên 'Equal [Animal]' trên 'Equal [Dog] ': http://www.scala-lang.org/node/4626. Các lớp thừa kế và kiểu lớp thực sự phức tạp để liên kết với nhau. – retronym

Trả lời

7

Nó sẽ không làm việc trong mọi trường hợp, nhưng như đã nói, bạn có thể thử này:

object foo { 
    trait Bar[Q[_]] 

    implicit object OptionBar extends Bar[Option] 

    def test[T, C[_], D](c: D)(implicit bar: Bar[C], ev: D <:< C[T]) =() 

    def main(args: Array[String]) { 
    test(Some(42)) //??? 
    } 
} 

Điều thú vị là, điều này không suy ra, mặc dù nó thể hiện điều tương tự:

def test[T, C[_], D <: C[T]](c: D)(implicit bar: Bar[C]) =() 

Để tìm hiểu thêm về <:<, xem:

+0

Điều này làm việc, tuy nhiên nếu bạn thêm một ngầm cho Bar trong phạm vi đó, nói 'đối tượng ẩn ListBar mở rộng Bar [List]' bạn nhận được một lỗi "mơ hồ giá trị tiềm ẩn". – Landei

+0

Tôi trả tiền thưởng cho câu trả lời này, bởi vì nó cho thấy một kỹ thuật tốt và giải quyết các câu hỏi ban đầu, mà không được xây dựng chính xác đủ. Tuy nhiên tôi vẫn đánh giá cao để có được gợi ý làm thế nào để giải quyết các vấn đề "ambiguos ngầm giá trị" vấn đề. – Landei

+0

Vâng, ba năm và vài phiên bản của Scala sau đó, nó không có vẻ là một câu trả lời tồn tại. (Tôi đang đối mặt với cùng một thách thức.) – Tim

5

Đó là bởi vì Some(42) là một loại hình cụ thể hơn Option[Int]. Đó là Some[Int]. Xem mã thay thế bên dưới:

object foo { 

    trait Bar[Q[_]] 

    implicit object OptionBar extends Bar[Option] 

    def test[T, C[_]](c: C[T])(implicit bar: Bar[C]) =() 

    def main(args: Array[String]) { 
     test(Option(42)) 
    } 
} 
+1

Tôi không thực sự biện hộ bằng cách sử dụng 'Option.apply' trừ khi sử dụng nó để mã hóa một kiểm tra null. Ngẫu nhiên, với scalaz, tôi sẽ viết '42.some' hoặc '42.pure [Option]', cả hai đều là 'Option [Int]'. – retronym

+0

@retronym - Tại sao bạn không ủng hộ bằng cách sử dụng 'Option.apply'? –

+1

Tôi sử dụng nó khi tôi có một tham chiếu có khả năng nullable muốn chuyển đổi thành 'Some' hoặc' None'. Tôi có thể đọc 'Some (x): Option [A]' và lý do là tôi sẽ có 'Some' mà không truy tìm nguồn gốc của' x'. Nếu đối số là một chữ, như trong ví dụ này, nó là okay mặc dù. – retronym