有时我需要编译时证明H <: HList
的每个元素都有T
类型。
它可以用以下代码表示:
import shapeless._
@annotation.implicitNotFound("Cannot prove that A =:= ${T} forAll A in ${H}")
trait ForAll[H <: HList, T]
object ForAll {
implicit def head[T]: ForAll[T :: HNil, T] = new ForAll[T :: HNil, T] {}
implicit def tail[T, HT <: HList](implicit ttail: ForAll[HT, T]): ForAll[T :: HT, T] = new ForAll[T :: HT, T] {}
}
// an example
def chain[H <: HList, A](hlist: H)(a: A)(implicit allAreFunctions: ForAll[H, (A => A)]): A = {
def iter(h: HList, ax: A): A = h match {
case HNil => ax
case (f: (A => A)) :: tail => iter(tail, f(ax))
}
iter(hlist, a)
}
val hlist1 = ((_: Int) + 1) :: ((_: Int) * 1) :: ((_: Int) - 2) :: HNil
val hlist2 = ((_: Int).toString) :: ((_: Int) + 1) :: ((_: Int) - 2) ::HNil
chain(hlist1)(1)
// chain(hlist2)(1) doesn't compile
我可以忽略有关可能的匹配错误的编译器警告,因为ForAll
实例证明代码是正确的。
没有形状可以实现这样的东西(或者有更好的选择)?
答案 0 :(得分:2)
ForAll
, shapeless.ops.hlist.LeftReducer
只是Poly
。例如
import shapeless.{::, HNil, Poly2}
import shapeless.ops.hlist.LeftReducer
object myPoly extends Poly2 {
implicit def `case`[A]: Case.Aux[A, A, A] = at((x, y) => x)
}
implicitly[LeftReducer.Aux[Int :: Int :: Int :: Int :: HNil, myPoly.type, Int]]//compiles
implicitly[LeftReducer[Int :: Int :: Int :: Int :: HNil, myPoly.type]]//compiles
// implicitly[LeftReducer.Aux[Int :: Int :: String :: Int :: HNil, myPoly.type, Int]]//doesn't compile
// implicitly[LeftReducer[Int :: Int :: String :: Int :: HNil, myPoly.type]]//doesn't compile
LeftReducer[Int :: Int :: Int :: Int :: HNil, myPoly.type].apply(1 :: 2 :: 3 :: 4 :: HNil)//1
// LeftReducer[Int :: Int :: String :: Int :: HNil, myPoly.type].apply(1 :: 2 :: "a" :: 4 :: HNil)//doesn't compile
(1 :: 2 :: 3 :: 4 :: HNil).reduceLeft(myPoly)//1
// (1 :: 2 :: "a" :: 4 :: HNil).reduceLeft(myPoly)//doesn't compile