簡體   English   中英

Shapeless:hlist編譯時出現foldLeft

[英]Shapeless: foldLeft on hlist compilation error

當我將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)

編譯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]

請注意,不成形限定runtimeList上方法HList這有效地計算一個List[Any]HList ,並且也是toList其中轉換方法HList到一個更精確地鍵入的List 不過,有趣的是,如何使用fold來執行此操作。

這里有一些皺紋。 首先要考慮的是您要在此處累積的List的類型。 您很可能希望結果列表的元素類型是要折疊的HList元素類型的最小上限(LUB)。 為了獲得該類型的結果,我們需要在運行時計算LUB。

我們還需要容納Nil作為初始值。 NilList[Nothing]類型的值,在我們需要解析由List[T]索引的隱式情況下,這是有問題的。 類型變量T必須在Nothing實例化才能匹配Nil的類型,但是不幸的是,Scala的類型推斷器將Nothing作為類型變量的值視為“未解決”……這是隱式解析的結果會虛假地失敗。 要變通解決此問題,我們必須為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。

問題是您在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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM