7

我有这种情况(精简到基本部分)

class Foo[L <: HList](columns: L) {

  class toRecord(row: Row) extends Poly1 {
    implicit def caseColumn[T] = at[Column[T]] { /* map to a record field */ }
  }

  def asRecord = {
    val resultSet: Stream[Row] = // computation to get result set
    resultSet.map { row =>        
      val m = new toRecord(row) // this can't work
      columns.map(m)
    }
  }

}

这不起作用,因为map需要一个稳定的标识符而m不是。所以我需要Poly1 singleton objects在结果集中有尽可能多的行。

这是此处讨论的相同问题:https ://groups.google.com/forum/#!topic/shapeless-dev/P5DXRgnzqkY ,但我找不到使这项工作的方法。

在链接的讨论中,Miles Sabin 提出了 a foldwith aPoly2而不是 a mapwith a Poly1,但我不知道如何在我的案例中使用这个建议。

4

1 回答 1

5

好的,我终于设法使用 aPoly2foldRight模拟参数图。

这是一个了解这个想法的例子

object toRecord extends Poly2 {
  implicit def caseColumn[A, B] = at[Column[A], (Row, B)] {
    case (col, (row, acc)) => 
      val field = doMyThingy(row, col) // "map" `col` to a recordField using `row` as parameter 
      (row, field :: acc)
  }
}

def asRecord[L <: HList, O <: HList](
  implicit folder: RightFolder[L, (Row, HNil.type), toRecord.type, (Row, O)]
): Stream[O] = {
  val resultSet: Stream[Row] = // computation to get result set
  resultSet.map { row => columns.foldRight((row, HNil))(toRecord)._2 }
}

所以这里的“技巧”是将参数作为折叠的初始值传递并在计算过程中携带它。

在计算中,我们使用row作为参数(我们的“参数映射”)对每个元素应用转换,然后我们只需将其附加到累加器。

完成后,我们最终得到一个包含row和映射的元组HList:我们可以简单地丢弃前者 ( ._2),我们就可以开始了。

于 2014-08-14T19:29:16.900 回答