I'm working on a CSV parsing library (tabulate). It uses simple type classes for encoding / decoding: encoding, for example, is done with instances of CellEncoder
(to encode a single cell) and RowEncoder
(to encode entire rows).
Using shapeless, I've found it pretty straightforward to automatically derive the following type class instances:
RowEncoder[A]
ifA
is a case class whose fields all have aCellEncoder
.RowEncoder[A]
ifA
is an ADT whose alternatives all have aRowEncoder
.CellEncoder[A]
ifA
is an ADT whose alternatives all have aCellEncoder
.
The thing is, this last one turns out to be almost entirely useless in real life situations: an ADT's alternatives are almost always case classes, and I cannot derive a CellEncoder
for a case class that has more than one field.
What I'd like to be able to do, however, is derive a CellEncoder
for case classes that have a single field whose type has a CellEncoder
. That would cover, for example, Either
, scalaz's \/
, cats' Xor
...
This is what I have so far:
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)
})
This works fine when used explicitly:
case class Bar(xs: String)
caseClass1CellEncoder[Bar, String]
res0: tabulate.CellEncoder[Bar] = tabulate.CellEncoder$$anon$2@7941904b
I can't however get it to work implicitly, the following fails:
implicitly[CellEncoder[Bar]]
>> could not find implicit value for parameter e: tabulate.CellEncoder[Test.this.Bar]
I've also tried the following, with no more success:
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)
})
Am I missing something? Is what I'm trying to do even possible?