簡體   English   中英

如何使用foldRight / foldLeft將HList轉換為另一個HList

[英]How to transform an HList to another HList with foldRight/foldLeft

這個問題來自我之前的問題: HList#foldLeft()返回什么?

我有這種情況:

class Cursor {
}

trait Column[T] {
   def read(c: Cursor, index: Int): T
}

object Columns {
    object readColumn extends Poly2 {
        implicit def a[A, B <: HList] = at[Column[A], (B, Cursor, Int)] { case (col, (values, cursor, index)) ⇒
            (col.read(cursor, index) :: values, cursor, index+1)
        }
    }

    def readColumns[A <: HList, B <: HList](c: Cursor, columns: A)(implicit l: RightFolder.Aux[A, (HNil.type, Cursor, Int), readColumn.type, (B, Cursor, Int)]): B =
        columnas.foldRight((HNil, c, 0))(readColumn)._1
}

此代碼嘗試讀取多個列的值。

如果我調用readColumns(cursor, new Column[String] :: new Column[Int] :: HNil) ,我希望得到String :: Int :: HNil

readColumns()方法編譯好,但編譯器抱怨具體調用中的readColumns()

什么是正確的工作方式?

更新1

這是我用2列調用時收到的確切錯誤消息:

could not find implicit value for parameter l: 
shapeless.ops.hlist.RightFolder.Aux[shapeless.::[Column[String],shapeless.::
[Column[String],shapeless.HNil]],(shapeless.HNil.type, android.database.Cursor, Int),readColumn.type,(B, android.database.Cursor, Int)]

不知道如何幫助編譯器。 :-(

更新2

問題:為什么在readColumns()的隱含參數中指定HNil.typeRightFolder.Aux[A, (HNil.type, Cursor, Int), readColumn.type, (B, Cursor, Int)]

更新以解決編輯問題

這是一個完整的工作示例:

class Cursor {}

trait Column[T] {
   def read(c: Cursor, index: Int): T
}

import shapeless._, ops.hlist.RightFolder

object Columns {
  object readColumn extends Poly2 {
    implicit def a[A, B <: HList]: Case.Aux[
      Column[A],
      (B, Cursor, Int),
      (A :: B, Cursor, Int)
    ] = at[Column[A], (B, Cursor, Int)] {
      case (col, (values, cursor, index)) =>
        (col.read(cursor, index) :: values, cursor, index + 1)
    }
  }

  def readColumns[A <: HList, B <: HList](c: Cursor, columns: A)(implicit
    l: RightFolder.Aux[
      A,
      (HNil, Cursor, Int),
      readColumn.type,
      (B, Cursor, Int)
    ]
  ): B = columns.foldRight((HNil: HNil, c, 0))(readColumn)._1
}

然后:

val stringColumn = new Column[String] {
  def read(c: Cursor, index: Int) = "foo"
}

val intColumn = new Column[Int] {
  def read(c: Cursor, index: Int) = 10
}

Columns.readColumns(new Cursor, stringColumn :: intColumn :: HNil)

這編譯得很好,並且在2.0.0和2.1.0-RC1上做了我期望的事情。

我應該在我的原始答案中提到使用HNil.type這樣並不理想 - 它工作正常,但在HNil的參數中明確鍵入foldRightHNil是一個更好的解決方案。 請注意,您必須執行其中一個,因為HNil的靜態類型是HNil.type ,而RightFolder在其第二個參數中不是協變的。

原始答案

你的readColumn定義中有一個非常小的錯誤 - 你正在返回一個Tuple4 ,但你想返回一個Tuple3 以下應該有效:

    object readColumn extends Poly2 {
       implicit def a[A, B <: HList]: Case.Aux[
         Column[A],
         (B, Cursor, Int),
         (A :: B, Cursor, Int)
       ] = at[Column[A], (B, Cursor, Int)] {
          case (col, (values, cursor, index)) =>
           (col.read(cursor, index) :: values, cursor, index+1)
       }
    }

對於任何隱式方法提供顯式返回類型通常是一個好主意,因為無關的原因與隱式解析有關,但在這種情況下明確返回類型也會很快發現錯誤。

暫無
暫無

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

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