简体   繁体   English

Shapeless:hlist编译时出现foldLeft

[英]Shapeless: foldLeft on hlist compilation error

Can not get foldLeft working on HList when folding to List, when i fold Hlist to a string everything works fine. 当我将Hlist折叠为字符串时,折叠到List时无法在HList上使用foldLeft。

object wrapInList extends Poly1 {
  implicit def intCase = at[Int]{v => List(v)}
  implicit def stringCase = at[String]{v => List(v)}
}

object mergeToString extends Poly1 {
  implicit def intCase = at[Int](_.toString())
  implicit def stringCase = at[String](identity)
}

object foldListPoly extends Poly2 {
  implicit  def foldToList[T](implicit st: wrapInList.Case.Aux[T, List[T]]) =
    at[List[T], T]{ (acc, t) => acc ::: wrapInList(t) }
  implicit def foldToString[T](implicit st: mergeToString.Case.Aux[T, String]) =
    at[String, T]{ (acc, t) => acc + mergeToString(t)}
}

val hList = "aoeu" :: 42 :: HNil
val foldedHlist = hList.foldLeft("")(foldListPoly)
val foldedHList2 = hList.foldLeft(Nil)(foldListPoly)

Erorr on compiling foldedHList2 编译folderHList2时出错

could not find implicit value for parameter folder:
shapeless.ops.hlist.LeftFolder[shapeless.::[String,shapeless.::[Int,shapeless.HNil]],scala.collection.immutable.Nil.type,com.test.Test.foldListPoly.type]

Please note that shapeless defines a runtimeList method on HList which efficiently computes a List[Any] from an HList , and also a toList method which converts an HList to a more precisely typed List . 请注意,不成形限定runtimeList上方法HList这有效地计算一个List[Any]HList ,并且也是toList其中转换方法HList到一个更精确地键入的List Nevertheless, it's interesting to see how this operation can be performed using fold . 不过,有趣的是,如何使用fold来执行此操作。

There are a couple of wrinkles here. 这里有一些皱纹。 The first thing to consider is what the type of the List you are accumulating here should be. 首先要考虑的是您要在此处累积的List的类型。 Most likely you would want the element type of the resulting list to be the least upper bound (LUB) of the types of the elements of the HList you're folding over. 您很可能希望结果列表的元素类型是要折叠的HList元素类型的最小上限(LUB)。 To get a result of that type we need to compute LUBs as we go. 为了获得该类型的结果,我们需要在运行时计算LUB。

We also need to accommodate Nil as the initial value. 我们还需要容纳Nil作为初始值。 Nil is a value of type List[Nothing] and this is problematic in cases where we need to resolve an implicit indexed by List[T] . NilList[Nothing]类型的值,在我们需要解析由List[T]索引的隐式情况下,这是有问题的。 The type variable T would have to be instantiated at Nothing to match the type of Nil , but unfortunately Scala's type inferencer treats the type Nothing as the value of a type variable as meaning "unsolved" ... the result of this is that implicit resolution would fail spuriously. 类型变量T必须在Nothing实例化才能匹配Nil的类型,但是不幸的是,Scala的类型推断器将Nothing作为类型变量的值视为“未解决”……这是隐式解析的结果会虚假地失败。 To work around this problem we have to provide an explicit case of foldListPoly for Nil.type . 要变通解决此问题,我们必须为Nil.type提供一个foldListPoly的显式实例。

Putting this together we end up with, 综合起来,我们最终得到了,

object wrapInList extends Poly1 {
  implicit def default[T] = at[T]{v => List(v)}
}

object foldListPoly extends Poly2 {
  implicit  def foldToListNil[U](implicit st: wrapInList.Case.Aux[U, List[U]]) =
    at[Nil.type, U]{ (acc, u) => wrapInList(u) }

  implicit  def foldToList[T, U, L, LL](
    implicit st: wrapInList.Case.Aux[U, List[U]],
    lub: Lub[T, U, L],
    llub: Lub[List[T], List[U], LL],
    ev: LL =:= List[L]
  ) = at[List[T], U]{ (acc, u) => llub.left(acc) ::: llub.right(wrapInList(u)) }
}

scala> ("aoeu" :: 42 :: HNil).foldLeft(Nil)(foldListPoly)
res0: List[Any] = List(aoeu, 42)

scala> (13 :: 23 :: HNil).foldLeft(Nil)(foldListPoly)
res1: List[Int] = List(13, 23)

scala> (23 :: true :: HNil).foldLeft(Nil)(foldListPoly)
res2: List[AnyVal] = List(23, true)

Notice that in each case the element type of the resulting list is the LUB of the element types of the HList . 请注意,在每种情况下,结果列表的元素类型都是HList元素类型的LUB。

The problem is that you generate a List[String] for "aoeu" in wrapInList which isn't compatible with the next element of hList (42, which is an Int ). 问题是您在wrapInList为“ aoeu”生成了一个List[String] ,它与hList的下一个元素(42,它是一个Int )不兼容。 If you can live with List[Any] (as opposed to the least upper bound), you can do it like this: 如果您可以使用List[Any] (而不是最小上限),则可以这样做:

object wrapInList extends Poly1 {
  implicit def intCase = at[Int]{v => List[Any](v)}
  implicit def stringCase = at[String]{v => List[Any](v)}
}

object foldListPoly extends Poly2 {
  implicit  def foldToList[T](implicit st: wrapInList.Case.Aux[T, List[Any]]) =
    at[List[Any], T]{ (acc, t) => acc ::: wrapInList(t) }
}

Additionally, you have to explicitly type Nil as List[Any] : 另外,您必须显式键入Nil作为List[Any]

val foldedHList2 = hList.foldLeft(Nil:List[Any])(foldListPoly)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM