Shapeless: foldLeft on hlist 编译错误
Shapeless: foldLeft on hlist compilation error
折叠到 List 时无法让 foldLeft 在 HList 上工作,当我将 Hlist 折叠到字符串时一切正常。
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)
编译 foldedHList2 时出错
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]
问题是您在 wrapInList
中为 "aoeu" 生成了一个 List[String]
,它与 hList
的下一个元素不兼容(42,这是一个Int
)。如果您可以接受 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) }
}
此外,您必须明确键入 Nil
作为 List[Any]
:
val foldedHList2 = hList.foldLeft(Nil:List[Any])(foldListPoly)
请注意,shapeless 在 HList
上定义了一个 runtimeList
方法,它可以从 HList
有效地计算出 List[Any]
,还有一个 toList
方法可以将 HList
转换为更精确类型化的 List
。尽管如此,看看如何使用 fold
.
执行此操作还是很有趣的
这里有一些皱纹。首先要考虑的是你在这里积累的 List
的类型应该是什么。您很可能希望结果列表的元素类型是您要折叠的 HList
元素类型的最小上限 (LUB)。要获得该类型的结果,我们需要在进行时计算 LUB。
我们还需要容纳Nil
作为初始值。 Nil
是类型 List[Nothing]
的值,在我们需要解析由 List[T]
索引的隐式索引的情况下,这是有问题的。类型变量 T
必须在 Nothing
处实例化以匹配 Nil
的类型,但不幸的是 Scala 的类型推断器将类型 Nothing
视为类型变量的值意思是 "unsolved" ... 其结果是隐式解析会虚假地失败。要解决此问题,我们必须为 Nil.type
.
提供 foldListPoly
的显式案例
把这些放在一起我们最终得到,
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)
请注意,在每种情况下,结果列表的元素类型都是 HList
的元素类型的 LUB。
折叠到 List 时无法让 foldLeft 在 HList 上工作,当我将 Hlist 折叠到字符串时一切正常。
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)
编译 foldedHList2 时出错
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]
问题是您在 wrapInList
中为 "aoeu" 生成了一个 List[String]
,它与 hList
的下一个元素不兼容(42,这是一个Int
)。如果您可以接受 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) }
}
此外,您必须明确键入 Nil
作为 List[Any]
:
val foldedHList2 = hList.foldLeft(Nil:List[Any])(foldListPoly)
请注意,shapeless 在 HList
上定义了一个 runtimeList
方法,它可以从 HList
有效地计算出 List[Any]
,还有一个 toList
方法可以将 HList
转换为更精确类型化的 List
。尽管如此,看看如何使用 fold
.
这里有一些皱纹。首先要考虑的是你在这里积累的 List
的类型应该是什么。您很可能希望结果列表的元素类型是您要折叠的 HList
元素类型的最小上限 (LUB)。要获得该类型的结果,我们需要在进行时计算 LUB。
我们还需要容纳Nil
作为初始值。 Nil
是类型 List[Nothing]
的值,在我们需要解析由 List[T]
索引的隐式索引的情况下,这是有问题的。类型变量 T
必须在 Nothing
处实例化以匹配 Nil
的类型,但不幸的是 Scala 的类型推断器将类型 Nothing
视为类型变量的值意思是 "unsolved" ... 其结果是隐式解析会虚假地失败。要解决此问题,我们必须为 Nil.type
.
foldListPoly
的显式案例
把这些放在一起我们最终得到,
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)
请注意,在每种情况下,结果列表的元素类型都是 HList
的元素类型的 LUB。