2013-06-27 23 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'中,一切似乎都按預期工作。 –