2013-05-22 15 views
9

Giả sử chúng ta có các lớp học và một số giá trị (trong Scala) sau:Bản đồ trên HList không thành công với tuýp phụ của loại chung trong Scala & hình thù

class A[T](val x: T) 
class B[T](x: T, val y: T) extends A[T](x) 

val x1 = new A("test") 
val x2 = new B(1,2) 
val x3 = new B("foo","bar") 
val x4 = new A(1) 

Hơn nữa, chúng tôi xác định giá trị hàm đa hình sau (sử dụng hình thù) :

object f extends (A ~> Option) { 
    def apply[T](s: A[T]) = Some(s.x) 
} 

Bây giờ chúng ta có thể gọi:

f(x1); f(x2); f(x3); f(x4) 

Mà tất cả thành công (và nên IMHO). Tuy nhiên:

val list = x1 :: x2 :: x3 :: x4 :: HNil 
list.map(f) 

// could not find implicit value for parameter mapper: 
// shapeless.Mapper[f.type,shapeless.::[A[String],shapeless.::[ 
// B[Int],shapeless.::[B[String],shapeless.::[A[Int],shapeless.HNil]]]]] 

đâu tôi đã mong đợi:

Some("test") :: Some(1) :: Some("foo") :: Some(1) :: HNil 

Lưu ý rằng công trình này:

val list2 = x1 :: x4 :: HNil // only instances of A 
list2.map(f) 

CẬP NHẬT

Dường như nếu chúng ta xác định từng trường hợp riêng biệt, được rồi:

object f extends Poly1 { 
    implicit def caseA[T] = at[A[T]]{s => Some(s.x)} 
    implicit def caseB[T] = at[B[T]]{s => Some(s.x)} 
} 

Tuy nhiên, cố gắng thể hiện điều này một chút thông minh hơn, không làm việc (thậm chí không cho các ứng dụng đơn giản):

object f extends Poly1 { 
    implicit def caseA[T, S <: A[T]] = at[S]{s => Some(s.x)} 
} 
+2

Tôi không thể cung cấp câu trả lời đầy đủ vào lúc này, nhưng cách khắc phục đơn giản nhất là sử dụng chế độ xem được gắn cho 'S' trong phiên bản' f' cuối cùng của bạn (nghĩa là 'S <% A [T]') . Hoặc ít nhất điều đó sẽ hoạt động và không yêu cầu bạn thêm các trường hợp cho mỗi loại phụ của 'A'. –

+0

@TravisBrown Cảm ơn rất nhiều vì câu trả lời nhanh. Điều đó thực sự có vẻ hiệu quả. Tôi thực sự mong muốn biết tại sao, nếu bạn có một câu trả lời hoặc con trỏ đơn giản. Nếu không -> mã đào – gzm0

Trả lời

9

lựa chọn tốt nhất của bạn là một trong những @ TravisBrown của gợi ý để sử dụng một cái nhìn bị ràng buộc,

object f extends Poly1 { 
    implicit def caseA[T, S <% A[T]] = at[S]{s => Some(s.x)} 
} 

hay, ít nhiều tương đương, một loại hạn chế,

object f2 extends Poly1 { 
    implicit def caseA[S, T](implicit ev : S <:< A[T]) = at[S]{s => Some(s.x)} 
} 

hoặc một biến thể trên hai trường hợp của bạn giải pháp mà các yếu tố ra sự tương đồng,

object f3 extends Poly1 { 
    def asub[T](s: A[T]) = Some(s.x) 
    implicit def caseA[T] = at[A[T]](asub) 
    implicit def caseB[T] = at[B[T]](asub) 
} 

Nó không chắc rằng giá trị chức năng đa hình hình thù sẽ được thay đổi để hỗ trợ trực tiếp các loại kiểu lập luận sai cần thiết để làm công việc định nghĩa ban đầu như bạn muốn, bởi vì điều đó sẽ xung đột với khả năng (IMO mong muốn cao) để phân biệt chính xác các trường hợp loại cụ thể rất chính xác.

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