简体   繁体   English

如何使用foldRight / foldLeft将HList转换为另一个HList

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

This question is derived from my previous question: What does HList#foldLeft() return? 这个问题来自我之前的问题: HList#foldLeft()返回什么?

I have this scenario: 我有这种情况:

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
}

This code, tries to read the values of several columns. 此代码尝试读取多个列的值。

If I call readColumns(cursor, new Column[String] :: new Column[Int] :: HNil) , I expect to get String :: Int :: HNil . 如果我调用readColumns(cursor, new Column[String] :: new Column[Int] :: HNil) ,我希望得到String :: Int :: HNil

The readColumns() method compiles ok, but the compiler complains about implicits in concrete invocations. readColumns()方法编译好,但编译器抱怨具体调用中的readColumns()

What is the right way of working?. 什么是正确的工作方式?

UPDATE 1 : 更新1

Here is the exact error message I'm receiving when invoking with 2 columns: 这是我用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)]

Don't know how to help the compiler. 不知道如何帮助编译器。 :-( :-(

UPDATE 2 : 更新2

Question: why specify HNil.type in the implicit parameter of readColumns() : RightFolder.Aux[A, (HNil.type, Cursor, Int), readColumn.type, (B, Cursor, Int)] ? 问题:为什么在readColumns()的隐含参数中指定HNil.typeRightFolder.Aux[A, (HNil.type, Cursor, Int), readColumn.type, (B, Cursor, Int)]

Update to address edits 更新以解决编辑问题

Here's a complete working example: 这是一个完整的工作示例:

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
}

And then: 然后:

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)

This compiles just fine and does what I'd expect on both 2.0.0 and 2.1.0-RC1. 这编译得很好,并且在2.0.0和2.1.0-RC1上做了我期望的事情。

And I should have mentioned in my original answer that using HNil.type like that isn't ideal—it works just fine, but explicitly typing the HNil in the argument to foldRight as HNil is a better solution. 我应该在我的原始答案中提到使用HNil.type这样并不理想 - 它工作正常,但在HNil的参数中明确键入foldRightHNil是一个更好的解决方案。 Note that you have to do one or the other, since the static type of HNil is HNil.type , and RightFolder isn't covariant in its second argument. 请注意,您必须执行其中一个,因为HNil的静态类型是HNil.type ,而RightFolder在其第二个参数中不是协变的。

Original answer 原始答案

There's a very minor error in your readColumn definition—you're returning a Tuple4 , but you want to return a Tuple3 . 你的readColumn定义中有一个非常小的错误 - 你正在返回一个Tuple4 ,但你想返回一个Tuple3 The following should work: 以下应该有效:

    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)
       }
    }

It's usually a good idea to provide an explicit return type for any implicit method for unrelated reasons having to do with implicit resolution, but in this case being explicit about the return type also turns up the error pretty quickly. 对于任何隐式方法提供显式返回类型通常是一个好主意,因为无关的原因与隐式解析有关,但在这种情况下明确返回类型也会很快发现错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM