我有以下方法:
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的大小相同,并且只包含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)
这是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"
}