为具有恰好一个字段的案例类派生类型类实例

Nic*_*udo 5 scala shapeless

我正在研究CSV解析库(制表).它使用简单的类型类进行编码/解码:例如,编码是通过CellEncoder(编码单个单元格)和RowEncoder(编码整行)的实例完成的.

使用无形,我发现自动派生以下类型类实例非常简单:

  • RowEncoder[A]if A是一个案例类,其字段都有一个CellEncoder.
  • RowEncoder[A]如果A是ADT,其替代品都有RowEncoder.
  • CellEncoder[A]如果A是ADT,其替代品都有CellEncoder.

事实是,最后一个在现实生活中几乎完全无用:ADT的替代品几乎总是案例类,而且我不能CellEncoder为具有多个字段的案例类派生.

然而,我希望能够做的是派生一个CellEncoder具有单个字段的案例类,其类型具有CellEncoder.这将涵盖,例如Either,scalaz's \/,cats' Xor......

这是我到目前为止:

implicit def caseClass1CellEncoder[A, H](implicit gen: Generic.Aux[A, H :: HNil], c: CellEncoder[H]): CellEncoder[A] =
    CellEncoder((a: A) => gen.to(a) match {
      case h :: t => c.encode(h)
    })
Run Code Online (Sandbox Code Playgroud)

这明确使用时工作正常:

case class Bar(xs: String)
caseClass1CellEncoder[Bar, String]
res0: tabulate.CellEncoder[Bar] = tabulate.CellEncoder$$anon$2@7941904b
Run Code Online (Sandbox Code Playgroud)

然而,我不能隐含地工作,以下失败:

implicitly[CellEncoder[Bar]]
>> could not find implicit value for parameter e: tabulate.CellEncoder[Test.this.Bar]
Run Code Online (Sandbox Code Playgroud)

我也试过以下,没有更多的成功:

implicit def testEncoder[A, H, R <: H :: HNil](implicit gen: Generic.Aux[A, R], c: CellEncoder[H]): CellEncoder[A] =
      CellEncoder((a: A) => gen.to(a) match {
        case h :: t => c.encode(h)
      })
Run Code Online (Sandbox Code Playgroud)

我错过了什么吗?我正在努力做甚么可能吗?

Tra*_*own 3

正确推断有点棘手H,但您可以通过一个<:<实例来做到这一点:

import shapeless._

case class CellEncoder[A](encode: A => String)

implicit val stringCellEncoder: CellEncoder[String] = CellEncoder(identity)
implicit val intCellEncoder: CellEncoder[Int] = CellEncoder(_.toString)

case class Bar(xs: String)

implicit def caseClass1CellEncoder[A, R, H](implicit
  gen: Generic.Aux[A, R],
  ev: R <:< (H :: HNil),
  c: CellEncoder[H]
): CellEncoder[A] = CellEncoder(
  (a: A) => ev(gen.to(a)) match {
    case h :: t => c.encode(h)
  }
)
Run Code Online (Sandbox Code Playgroud)

CellEncoder(为了完整的工作示例,我编写了一个简单的示例。)

这是有效的,因为R可以在编译器查找实例时进行推断,然后可以在查找 的值时Generic.Aux[A, R]指导 的推断。Hev