Tôi đang làm việc trên một thư viện nhỏ cho các mô hình kinh tế kiểm tra các đơn vị của các thực thể, sử dụng các loại, ví dụ: thay vì val apples = 2.0
, chúng tôi viết val apples = GoodsAmount[KG, Apples](2.0)
. Để tạo bó hàng hóa, tôi đang cố gắng sử dụng HLists từ thư viện không có hình dạng. Điều này làm việc tốt, nhưng trong một số trường hợp tôi không thể được như mã chung như tôi thích. Xem ví dụ vấn đề sau.Shapeless: Kiểm tra loại ràng buộc của các chức năng đa hình
Tôi bắt đầu bằng một mã đơn giản giải thích những gì tôi muốn chuyển thành không có hình dạng. Chúng tôi tạo ra hai lớp, đại diện cho Km, các Miles khác. Nó nên được phép thêm các lớp Km, nhưng không phải dặm. Rằng tôi sử dụng một kiểu trừu tượng T chủ yếu là động lực làm thư viện phức tạp hơn của chúng ta. Và cuộc gọi gián tiếp đến chức năng '+' chỉ là vì chúng ta cần một cái gì đó tương tự trong trường hợp không có hình dạng phía sau.
trait Foo {
type T
val v: Double
def +[B <: Foo](other: B)(implicit ev: this.T =:= other.T) = v + other.v
}
trait _Km
trait _Miles
case class Km(v: Double) extends Foo { type T = _Km }
case class Miles(v: Double) extends Foo { type T = _Miles }
object ExampleSimple extends App {
def add[A <: Foo, B <: Foo](a: A, b: B)(implicit ev: a.T =:= b.T) = { a + b }
add(Km(1), Km(2))
// add(Km(1), Miles(2)) /* does not compile as intended */
}
Điều này hoạt động như dự định. Nhưng cần phải kiểm tra Loại Contraint trên chức năng 'thêm'. nỗ lực của tôi để mở rộng này để HLists trông như thế này:
object ExampleShapeless extends App {
import shapeless._
val l1 = Km(1) :: Km(2) :: HNil
val l2 = Km(4) :: Km(3) :: HNil
object add extends Poly1 {
implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a, b) => a + b }
}
(l1 zip l2).map(add)
}
Nhưng điều này tạo ra các thông báo sau lỗi (sử dụng Scala 2.10.2):
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:50: Cannot prove that a.T =:= b.T.
[error] implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a: Foo, b) => a + b }
[error] ^
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:54: could not find implicit value for parameter mapper: shapeless.Mapper[ExampleShapeless.add.type,shapeless.::[(Km, Km),shapeless.::[(Km, Km),shapeless.HNil]]]
[error] (l1 zip l2).map(add)
Lỗi đầu tiên cần được cố định, trong trường hợp rằng tôi có thể thêm một ràng buộc kiểu vào hàm caseTuple, nhưng thành thật mà nói, tôi đã không hiểu cách hàm tại đang làm việc và nơi tôi có thể thêm tham số bằng chứng ngầm. Và tôi cũng không biết, những gì tôi phải làm, để Mapper sẽ tìm thấy giá trị tiềm ẩn của anh ta.
Một phiên bản ít generic, nơi tôi replase chức năng caseTuple với
implicit def caseTuple = at[(Km,Km)] { case (a, b) => a + b }
hoạt động tốt, nhưng sẽ cần phải viết rất nhiều mã dư thừa (okay, giải pháp này sẽ vẫn tốt hơn là giải pháp hiện tại của chúng tôi sử dụng Tuples). Ai đó có thể cho tôi một gợi ý làm thế nào tôi có thể giải quyết vấn đề này?
Cảm ơn, Klinke
Bạn có thể thử định nghĩa 'Foo' của bạn như sau:' trait Foo [T <: Foo] {v: Double; + (t T): T = ...} '. 'class Km (val v: Double) mở rộng Foo [Km]'. 'ngầm định def thêm [T] = tại [(Foo [T], Foo [T])]' – senia