Scala 为只有一个字段的案例类派生类型类实例

Scala 为只有一个字段的案例类派生类型类实例,scala,shapeless,Scala,Shapeless,我正在开发一个CSV解析库()。它使用简单的类型类进行编码/解码:例如,编码是通过CellEncoder(对单个单元格进行编码)和RowEncoder(对整行进行编码)的实例来完成的 使用shapeless,我发现自动派生以下类型类实例非常简单: RowEncoder[A]如果A是一个case类,其字段都有一个CellEncoder RowEncoder[A]如果A是一个ADT,其备选方案都有一个RowEncoder CellEncoder[A]如果A是一个ADT,其替代品都有一个CellEn

我正在开发一个CSV解析库()。它使用简单的类型类进行编码/解码:例如,编码是通过
CellEncoder
(对单个单元格进行编码)和
RowEncoder
(对整行进行编码)的实例来完成的

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

  • RowEncoder[A]
    如果
    A
    是一个case类,其字段都有一个
    CellEncoder
  • RowEncoder[A]
    如果
    A
    是一个ADT,其备选方案都有一个
    RowEncoder
  • CellEncoder[A]
    如果
    A
    是一个ADT,其替代品都有一个
    CellEncoder
问题是,最后一个在现实生活中几乎毫无用处:ADT的替代方案几乎都是case类,我无法为一个包含多个字段的case类派生出
CellEncoder

但是,我希望能够为具有单个字段的case类派生一个
CellEncoder
,该字段的类型为
CellEncoder
。这将包括,例如,
要么
,scalaz的
\/
,cats的
异或

这就是我到目前为止所做的:

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)
    })
当显式使用时,这可以很好地工作:

case class Bar(xs: String)
caseClass1CellEncoder[Bar, String]
res0: tabulate.CellEncoder[Bar] = tabulate.CellEncoder$$anon$2@7941904b
然而,我无法让它隐式工作,以下失败:

implicitly[CellEncoder[Bar]]
>> could not find implicit value for parameter e: tabulate.CellEncoder[Test.this.Bar]
我也尝试过以下方法,但没有成功:

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)
      })
implicit def testincoder[A,H,R gen.to(A)匹配{
案例h::t=>c.encode(h)
})

我遗漏了什么吗?我想做的是可能的吗?

正确推断
H
有点困难,但是你可以用
c.encode(H)来做
}
)
(为了提供一个完整的工作示例,我编写了一个简单的
CellEncoder


这是因为当编译器查找
Generic.Aux[A,R]时,可以推断出
R
实例,然后在查找
ev

的值时,可以引导
H
的推断,我需要仔细考虑这一点,但我可以确认它是有效的。巧合的是,我在Circe的代码中花费了大量时间来理解case类的自动类型类派生,因此感谢这两个例子nswer和Circe!我正在为这个问题的双重性而挣扎——写一个
CellDecoder
String=>a
),因为
R@NicolasRinaudo一个新问题是合适的。完成后,新问题就出现了。
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)
  }
)