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