【问题标题】:How to transform an HList to another HList with foldRight/foldLeft如何使用 foldRight/foldLeft 将 HList 转换为另一个 HList
【发布时间】:2015-01-25 03:42:20
【问题描述】:

这个问题来源于我之前的问题:What does HList#foldLeft() return?

我有这种情况:

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() 方法编译正常,但编译器抱怨具体调用中的隐式。

什么是正确的工作方式?

更新 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)]

【问题讨论】:

    标签: scala shapeless


    【解决方案1】:

    更新地址编辑

    这是一个完整的工作示例:

    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 并不理想——它工作得很好,但是在foldRight 的参数中明确键入HNilHNil 更好解决方案。请注意,您必须做一个或另一个,因为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)
           }
        }
    

    出于与隐式解析无关的原因,为任何隐式方法提供显式返回类型通常是个好主意,但在这种情况下,显式返回类型也会很快导致错误。

    【讨论】:

    • 谢谢,现在好多了。为什么我必须为readColumns() 隐式参数指定HNil.type?。它仍然不适用于具体的调用。 :-(
    • 嗯,当我设置一个简单的示例时,调用readColumns 对我有用。我去看看,但可能要到今天下午晚些时候才有机会。
    • 我已经用我收到的确切错误消息更新了问题,以便更好地诊断。
    • 请注意,在表达式HNil: HNil 中,第一项指的是object HNil,而第二项指的是trait HNil
    • 您的示例在 Scala REPL 中工作正常,但在常规源文件中却不行。我一直遇到编译器无法为readColumns() 生成隐式参数的问题。 Shapeless 很强大,但也很棘手。 :-(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多