如何从序列创建约束HList?

时间:2017-05-17 23:04:58

标签: scala shapeless

我有一个具有以下签名的构造函数:

class Event[DL <: HList](
  detailsIn: DL
)(implicit lbcr: LUBConstraint[DL, EventDetail[_]]) { ... 

在我的伴侣对象中:

  def apply[DL <: HList](
    detailIn: String*
  )(implicit lbcr: LUBConstraint[DL, EventDetail[String]]) =
    new Event(
      if (detailIn.map(deet => EventDetail(deet)).toList.size == 1)
        detailIn.map(deet => EventDetail(deet)).toList.toHList[String :: HNil].get
      else throw new NotImplementedException()
    )(lbcr)

不可否认,这种申请方法可以清理干净。

这会产生以下错误,我坦率地说该如何处理这个错误:

Error:(87, 7) type mismatch;
 found   : shapeless.LUBConstraint[DL,edu.cornell.ansci.dairy.econ.model.event.EventDetail[String]]
 required: shapeless.LUBConstraint[shapeless.::[String,shapeless.HNil],edu.cornell.ansci.dairy.econ.model.event.EventDetail[_]]

问题的第二部分:有没有办法使这个多态性超过detailIn的大小?根据我的其他读物,我假设没有,我认为在Scala中无法做到这一点。我能做的最好的事情是为detailIn字符串序列提供固定数量长度的便利,如果超过了,则该类的用户必须直接使用HList。

1 个答案:

答案 0 :(得分:2)

不要被这种类型错误吓到,这很明确,让我尝试自下而上键入apply方法的正文:

在最底部,你有一个String :: HNil

val e0: String :: HNil = e.toList.toHList[String :: HNil].get

if不会改变:

val e1: String :: HNil = 
  if (???) e0
  else throw new NotImplementedException()

因此,当您创建EventEvent.DL = String :: HNil

new Event[String :: HNil](e1)(lbcr)

lbcr的类型为LUBConstraint[DL, _],与LUBConstraint[String :: HNil, _]不兼容!

对于问题的第二部分,shapeless提供了一种比varargs更安全的替代方案:ProductArgs。以宏{object myfunction extends ProductArgs { def applyProduct[L <: HList](args: L) }而不是def myfunction(args: Any*)为基础,您可以使用HList代替Seq[String]来支持您的varargs。