I am working on a small library for economic models that test units of objects using types, for example. instead of val apples = 2.0 we write val apples = GoodsAmount[KG, Apples](2.0) . To create a product package, I am trying to use HLists from a formless library. This works great, but in some cases, I cannot be as general a code as I prefer. See the following problem.
I start with a simple code that explains what I want to shoot in formless. We create two classes depicting Km, the other Miles. It should be allowed to add Km classes, but not miles. The fact that I am using the abstract type T is mainly motivated by our more complex library. And the indirect call to the "+" function is only that we need something similar in the formless case.
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: aT =:= bT) = { a + b } add(Km(1), Km(2)) // add(Km(1), Miles(2)) /* does not compile as intended */ }
It works as intended. But for the add function, you need to have a Contraint check. My attempt to extend this to HLists is as follows:
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) }
But this generates the following error message (using Scala 2.10.2):
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:50: Cannot prove that aT =:= bT [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)
The first error should be fixed if I can add a type constraint to the caseTuple function, but to be honest, I do not understand how the at function works and where I can add an implicit proof parameter. And I also donβt know what should I do for Mapper to find its implicit value.
Less general version where I replace caseTuple function
implicit def caseTuple = at[(Km,Km)] { case (a, b) => a + b }
works fine, but you will need to write a lot of redundant code (well, this solution will be even better since our current solution uses Tuples). Can someone give me a hint how can I solve this problem?
Thanks, Klinke