I am working on a CSV parsing library ( tabulate ). It uses simple class types for encoding / decoding: for example, encoding is performed with instances of CellEncoder (for encoding a single cell) and RowEncoder (for encoding whole strings).
Using formlessness, I found it pretty simple to automatically get the following type class instances:
RowEncoder[A] if A is the case class, all fields of which have CellEncoder .RowEncoder[A] , if A is an ADT, all alternatives have a RowEncoder .CellEncoder[A] , if A is an ADT, all alternatives have CellEncoder .
The fact is that the latter is almost useless in real life situations: ADT alternatives are almost always case classes, and I can not get CellEncoder for the case class, which has more than one field.
However, I would like to be able to make CellEncoder for case classes that have one field of type CellEncoder . This will cover e.g. Either , scalaz \/ , 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 cannot get it to work implicitly, the following:
implicitly[CellEncoder[Bar]] >> could not find implicit value for parameter e: tabulate.CellEncoder[Test.this.Bar]
I also tried the following, without any 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 this what I'm trying to do is even possible?