HList 上的约束:检查类型的单次出现
Constraint on HList: check for single occurrence of a type
我正在尝试在 HList 上添加约束(来自 Shapeless):
- 它应该包含任意数量的
TA
类型的元素(从 0 到 N);
- 它应该包含一个且只有一个类型为
TB
的元素。
我的示例具有以下类型层次结构:
trait T
case class TA extends T
case class TB extends T
举个例子:
tb :: HNil
有效
ta :: tb ::HNil
有效
ta :: tb :: ta :: HNil
有效
ta :: HNil
无效
HNil
无效
我不知道如何将其表示为约束。
您可以使用自定义类型 class 来执行此操作,它证明只有一个 TB
并且所有其他元素都是 TA
。如果您想象以归纳方式构建此列表,您会发现有两种情况需要处理——要么您目前看到的所有内容都是 TA
(我们可以用 ToList[T, TA]
证明这一点)并且当前元素是 TB
,或者您已经看到一个 TB
而当前元素是 TA
:
import shapeless._, ops.hlist.{ ToList }
trait T
case class TA() extends T
case class TB() extends T
trait UniqueTB[L <: HList] extends DepFn1[L] {
type Out = TB
def apply(l: L): TB
}
object UniqueTB {
def apply[L <: HList](implicit utb: UniqueTB[L]): UniqueTB[L] = utb
def getTB[L <: HList](l: L)(implicit utb: UniqueTB[L]): TB = utb(l)
implicit def firstTB[T <: HList](
implicit tl: ToList[T, TA]
): UniqueTB[TB :: T] = new UniqueTB[TB :: T] {
def apply(l: TB :: T): TB = l.head
}
implicit def afterTB[T <: HList](
implicit utb: UniqueTB[T]
): UniqueTB[TA :: T] = new UniqueTB[TA :: T] {
def apply(l: TA :: T): TB = utb(l.tail)
}
}
然后:
scala> UniqueTB[TB :: HNil]
res0: UniqueTB[shapeless.::[TB,shapeless.HNil]] = UniqueTB$$anon@385c6929
scala> UniqueTB[TA :: TB :: HNil]
res1: UniqueTB[shapeless.::[TA,shapeless.::[TB,shapeless.HNil]]] = UniqueTB$$anon@682dd97e
scala> UniqueTB[TA :: TB :: TA :: HNil]
res2: UniqueTB[shapeless.::[TA,shapeless.::[TB,shapeless.::[TA,shapeless.HNil]]]] = UniqueTB$$anon@5ef48f82
scala> UniqueTB[TB :: HNil]
res3: UniqueTB[shapeless.::[TB,shapeless.HNil]] = UniqueTB$$anon@33be241
scala> UniqueTB[TA :: HNil]
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.::[TA,shapeless.HNil]]
UniqueTB[TA :: HNil]
^
scala> UniqueTB[HNil]
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.HNil]
UniqueTB[HNil]
^
scala> UniqueTB[TB :: TB :: HNil]
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.::[TB,shapeless.::[TB,shapeless.HNil]]]
UniqueTB[TB :: TB :: HNil]
^
我已经为类型 class 提供了 returns TB
的操作,但如果您不需要它,您可以将其保留为无方法。
我正在尝试在 HList 上添加约束(来自 Shapeless):
- 它应该包含任意数量的
TA
类型的元素(从 0 到 N); - 它应该包含一个且只有一个类型为
TB
的元素。
我的示例具有以下类型层次结构:
trait T
case class TA extends T
case class TB extends T
举个例子:
tb :: HNil
有效ta :: tb ::HNil
有效ta :: tb :: ta :: HNil
有效ta :: HNil
无效HNil
无效
我不知道如何将其表示为约束。
您可以使用自定义类型 class 来执行此操作,它证明只有一个 TB
并且所有其他元素都是 TA
。如果您想象以归纳方式构建此列表,您会发现有两种情况需要处理——要么您目前看到的所有内容都是 TA
(我们可以用 ToList[T, TA]
证明这一点)并且当前元素是 TB
,或者您已经看到一个 TB
而当前元素是 TA
:
import shapeless._, ops.hlist.{ ToList }
trait T
case class TA() extends T
case class TB() extends T
trait UniqueTB[L <: HList] extends DepFn1[L] {
type Out = TB
def apply(l: L): TB
}
object UniqueTB {
def apply[L <: HList](implicit utb: UniqueTB[L]): UniqueTB[L] = utb
def getTB[L <: HList](l: L)(implicit utb: UniqueTB[L]): TB = utb(l)
implicit def firstTB[T <: HList](
implicit tl: ToList[T, TA]
): UniqueTB[TB :: T] = new UniqueTB[TB :: T] {
def apply(l: TB :: T): TB = l.head
}
implicit def afterTB[T <: HList](
implicit utb: UniqueTB[T]
): UniqueTB[TA :: T] = new UniqueTB[TA :: T] {
def apply(l: TA :: T): TB = utb(l.tail)
}
}
然后:
scala> UniqueTB[TB :: HNil]
res0: UniqueTB[shapeless.::[TB,shapeless.HNil]] = UniqueTB$$anon@385c6929
scala> UniqueTB[TA :: TB :: HNil]
res1: UniqueTB[shapeless.::[TA,shapeless.::[TB,shapeless.HNil]]] = UniqueTB$$anon@682dd97e
scala> UniqueTB[TA :: TB :: TA :: HNil]
res2: UniqueTB[shapeless.::[TA,shapeless.::[TB,shapeless.::[TA,shapeless.HNil]]]] = UniqueTB$$anon@5ef48f82
scala> UniqueTB[TB :: HNil]
res3: UniqueTB[shapeless.::[TB,shapeless.HNil]] = UniqueTB$$anon@33be241
scala> UniqueTB[TA :: HNil]
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.::[TA,shapeless.HNil]]
UniqueTB[TA :: HNil]
^
scala> UniqueTB[HNil]
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.HNil]
UniqueTB[HNil]
^
scala> UniqueTB[TB :: TB :: HNil]
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.::[TB,shapeless.::[TB,shapeless.HNil]]]
UniqueTB[TB :: TB :: HNil]
^
我已经为类型 class 提供了 returns TB
的操作,但如果您不需要它,您可以将其保留为无方法。