Reputation: 6168
This question is tightly related to this one, but not identical: it's the same context but the opposite problem.
I'm trying to derive a CellDecoder[A]
, which is essentially a String => A
, for A
s that are case classes with a single field whose type has a CellDecoder
.
In order to do this, I need to require:
A
to be transformable to R
, where R
is a subtype of H :: HNil
.H
to have CellDecoder
instance.That is:
implicit def caseClassCellDecoder[A, R, H](implicit
gen: Generic.Aux[A, R],
ev: R <:< (H :: HNil),
d: CellDecoder[H]
): CellDecoder[A] = ???
The issue I'm having is that, once I've turned a String
to an H
through the relevant CellDecoder
instance, I'm kind of stuck: ev
allows me to turn an R
into an H :: HNil
, but not an H :: HNil
into an R
. Not having an R
, I can't use my Generic.Aux[A, R]
to get the final A
instance.
It turns out that casting my H :: HNil
into an R
works, but I'm not sure why and can't convince myself that it'll always be the case.
I thought about requiring R
to be strictly equal to H :: HNil
(that is, to have a R =:= HNil
), but then the implicits fail to resolve.
Is there a way to do what I'm trying to do?
Upvotes: 1
Views: 116
Reputation: 381
I did use =:=
instead of <:<
however swapped the sides of R
and H::HNil
and that seemed to work:
case class CellDecoder[A](decode: String => A)
implicit val stringCellDecoder: CellDecoder[String] = CellDecoder(identity)
implicit def caseClassCellDecoder[A, R, H](implicit
gen: Generic.Aux[A, R],
ev: (H :: HNil) =:= R,
d: CellDecoder[H]
): CellDecoder[A] = CellDecoder(
(str: String) => gen.from(ev(d.decode(str)::HNil))
)
So I was able to use it as follows:
case class TestDecoder(test: String)
def doDecode[A: CellDecoder](str: String): A = {
implicitly[CellDecoder[A]].decode(str)
}
doDecode[TestDecoder]("encoded value")
Upvotes: 2