【问题标题】:Constraint on HList: check for single occurrence of a typeHList 上的约束:检查类型的单次出现
【发布时间】:2016-08-30 20:21:37
【问题描述】:

我正在尝试在 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 无效

我不知道如何将其表达为约束。

【问题讨论】:

  • hlist中是否允许其他类型?
  • 不,只有扩展 T 的东西(除了 TA 和 TB 可能永远不会有任何其他类型)。

标签: scala shapeless


【解决方案1】:

您可以使用一个自定义类型类来做到这一点,该类证明只有一个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$1@385c6929

scala> UniqueTB[TA :: TB :: HNil]
res1: UniqueTB[shapeless.::[TA,shapeless.::[TB,shapeless.HNil]]] = UniqueTB$$anon$2@682dd97e

scala> UniqueTB[TA :: TB :: TA :: HNil]
res2: UniqueTB[shapeless.::[TA,shapeless.::[TB,shapeless.::[TA,shapeless.HNil]]]] = UniqueTB$$anon$2@5ef48f82

scala> UniqueTB[TB :: HNil]
res3: UniqueTB[shapeless.::[TB,shapeless.HNil]] = UniqueTB$$anon$1@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]
               ^

我已经为类型类提供了一个返回 TB 的操作,但如果你不需要它,你可以让它不使用方法。

【讨论】:

  • 我认为你可以使用 shapeless 已经提供的 IsHCons 类型类,而不是创建一个新的类。剩下的唯一事情是根据现有实例定义afterTB。你怎么看?
  • 其实没关系,别以为你能做到。 :|
  • @DenisRosca 是的,我不知道这会如何工作,但我可能会遗漏一些东西。
  • 非常感谢@TravisBrown!我只是不知道如何将它与值类型一起使用(例如:案例类 TA(值:字符串))。如何传递实例而不仅仅是类型?我确定我在这里遗漏了一些要点......
  • @AlbanDericbourg 我刚刚在答案中添加了一个getTB 方法。只需传递一个 hlist 值(将推断类型),如果 hlist 满足约束,它将编译,否则不会编译。
猜你喜欢
  • 1970-01-01
  • 2012-06-12
  • 1970-01-01
  • 2015-07-31
  • 1970-01-01
  • 2012-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多