如何从序列创建受限制的HList?

3

我有一个构造函数,其签名如下:

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)

不可否认,这个apply方法可以进行清理。

这将产生以下错误,我实在是不知道如何处理:

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个回答

2

不要被那个类型错误吓到,它非常明确,让我试着从底部向上输入你的apply方法的主体:

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

val e0: String :: HNil = e.toList.toHList[String :: HNil].get
< p >如果语句并不能改变这一点:< /p>
val e1: String :: HNil = 
  if (???) e0
  else throw new NotImplementedException()

因此,当您创建 Event 时,Event.DL = String :: HNil
new Event[String :: HNil](e1)(lbcr)

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

对于你问题的第二部分,shapeless提供了一种更安全的替代方案来使用可变参数:ProductArgs。通过宏和稍微复杂一些的定义支持,你可以像这样使用object myfunction extends ProductArgs { def applyProduct[L <: HList](args: L) } 来获取可变参数作为HList而不是Seq[String]


谢谢,这真的很有帮助。我还有一些其他问题,主要是需要将“_”替换为“T <: Any”。至少我已经让它通过了类型检查,会继续尝试使其达到可用状态,并在成功后进行更新。 - bbarker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接