2013-06-27 27 views
6

我正在为检查实体经济单位模型,使用类型,例如一个小型图书馆检查的类型约束而不是val apples = 2.0我们写val apples = GoodsAmount[KG, Apples](2.0)。为了创建一揽子商品,我试图使用无形库中的HList。这工作正常,但在某些情况下,我不能像我更喜欢的通用代码。见例如下面的问题。无形:多态函数

我先从一个简单的代码来解释我想提升到无形的东西。我们创建两个类,代表Km,另一个Miles。应该允许添加公里等级,但不允许里程。我使用抽象类型T的主要动机是我们更复杂的库。对'+'函数的间接调用仅仅是因为我们在后面的不成形情况下需要类似的东西。

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 */ 
} 

这按预期工作。但有必要对'添加'功能进行类型限制检查。我试图将其扩展到HLists看起来是这样的:

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) 
} 

但是,这产生了以下错误消息(使用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) 

的第一个错误应该是固定的,在案件我可以添加一个类型约束到caseTuple函数,但说实话,我还没有理解at函数是如何工作的以及我可以在哪里添加隐式证据参数。而且我也不知道,我必须做什么,以便Mapper能找到他的隐含价值。

一个不太通用版本,在那里我有

implicit def caseTuple = at[(Km,Km)] { case (a, b) => a + b } 

replase的caseTuple功能工作正常,但对我们目前的解决方案使用需要编写大量的冗余代码(好吧,这个解决方案将是犹未元组)。有人能给我一个提示,我怎么能解决这个问题?

感谢, Klinke

+0

你可以试着来定义你的'Foo'这样的:'特质富[T <:美孚] {V:双; +(t T):T = ...}'。 Km级(val v:Double)扩展Foo [Km]'。 'implicit def add [T] = at [(Foo [T],Foo [T])]' – senia

回答

7

您可以要求该类型成员加入一个类型参数的情况下,以匹配:

object add extends Poly1 { 
    implicit def caseTuple[_T, A <: Foo { type T = _T }] = at[(A, A)] { 
    case (a, b) => a + b 
    } 
} 

或者你可以使用一个存在的类型,因为你只有真正关心它们是相同的:

object add extends Poly1 { 
    implicit def caseTuple[A <: Foo { type T = _T } forSome { type _T }] = 
    at[(A, A)] { 
     case (a, b) => a + b 
    } 
} 

两个版本都会提供你想要的行为。

+0

谢谢,这工作正常也是我的更复杂的情况;-)但我仍然存在缺少隐式值的问题映射。我会尽力自己解决,但也许你可以在这里帮助我? – Klinke

+0

好的,找到了简化版本的解决方案,为A添加一个上下文来帮助。所以我现在''隐式def caseTuple [_t,A <:Foo {type T = _T} <%Foo {type T = _T}] = ...'这次解决方案并不容易翻译成我的完整版本,但希望我能解决新的问题。 – Klinke

+0

@Klinke:我不确定我是否理解这个问题 - 如果我将'add'复制并粘贴到'ExampleShapeless'中,一切似乎都按预期工作。 –