[英]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]
. Nil
是List[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.