此问题来自我之前的问题: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 :
问题:为什么在HNil.type
的隐式参数中指定readColumns()
:RightFolder.Aux[A, (HNil.type, Cursor, Int), readColumn.type, (B, Cursor, Int)]
?
答案 0 :(得分:5)
这是一个完整的工作示例:
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
的参数中明确键入foldRight
} HNil
是一个更好的解决方案。请注意,您必须执行其中一个操作,因为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)
}
}
为了与隐式解析有关的无关原因,为任何隐式方法提供显式返回类型通常是一个好主意,但在这种情况下,显式返回类型也会很快发现错误。