2016-09-30 48 views
1

我有以下方法:無形的:複雜HList約束

import shapeless._ 
import shapeless.UnaryTCConstraint._ 
def method[L <: HList : *->*[Seq]#λ](list: L) = println("checks") 

它讓我保證會發生以下情況:

val multipleTypes = "abc" :: 1 :: 5.5 :: HNil 
val onlyLists = Seq("abc") :: Seq(1) :: Seq(5.5) :: HNil 

method(multipleTypes) // throws could not find implicit value ... 
method(onlyList) // prints checks 

我怎樣才能增加method與另一個參數列表,是這樣的:

def method2[L <: HList : *->*[Seq]#λ, M <: HList](list: L)(builder: M => String) = println("checks") 

但是,由於HList M的大小必須與HList L a相同ND只包含在內類型HList L的元素讓我舉一個例子:

// This should work 
method2(Seq("abc") :: Seq(1) :: Seq(5.5) :: HNil){ 
    case a :: 1 :: d :: HNil => "works" 
} 
// This should throw some error at compile time, because the second element is Seq[Int] 
// therefore in the builder function I would like the second element to be of type Int. 
method2(Seq("abc") :: Seq(1) :: Seq(5.5) :: HNil){ 
    case a :: true :: d :: HNil => "fails" 
} 
// This should also fail because the HLists are not of the same length. 
method2(Seq("abc") :: Seq(1) :: Seq(5.5) :: HNil){ 
    case 1 :: d :: HNil => "fails" 
} 

如果我定義method2這樣的:

def method2[L <: HList : *->*[Seq]#λ](list: L)(builder: L => String) = println("checks") 

它幾乎解決了這個問題,唯一的事情,缺少的是建設者將具有類型Seq [T]而不是類型T的元素的元素。

+0

應該用什麼方法2的'結果(SEQ(「ABC」,「DEF」):: SEQ(1, 2,3):: Seq(5.5):: HNil){case a :: b :: c :: HNil => a.toString + b.toString + c.toString}'? – Kolmar

+0

它應該工作,因爲HList的大小相同,並且您對a,b和c的類型沒有限制,所以它們應該被正確地推斷爲'String','Int'和'Double'。 –

回答

2

這是ops.hlist.Comapped的情況。

你想要定義method2

def method2[L <: HList : *->*[Seq]#λ, M <: HList] 
    (list: L) 
    (builder: M => String) 
    (implicit ev: Comapped.Aux[L, Seq, M]) 

但是,這是行不通的,因爲類型M應類型檢查的builder參數之前的計算。

所以實際實現變得像:

class Impl[L <: HList : *->*[Seq]#λ, M <: HList] 
    (list: L) 
    (implicit ev: Comapped.Aux[L, Seq, M]) 
{ 
    def apply(builder: M => String) = println("checks") 
} 

def method2[L <: HList : *->*[Seq]#λ, M <: HList] 
    (list: L) 
    (implicit ev: Comapped.Aux[L, Seq, M]) = new Impl[L, M](list) 

而且你不能直接調用它。你可以使用一個額外的apply,或者一些其他的方法來提供隱式的隱含參數列表:

method2(Seq("abc") :: Seq(1) :: Seq(5.5) :: HNil) apply { 
    case a :: 1 :: d :: HNil => "works" 
}