使用单个字段派生 case 类 的解码器实例

Deriving decoder instances of case classes with a single field

此问题与 密切相关,但不完全相同:上下文相同但问题相反。

我正在尝试导出一个 CellDecoder[A],它本质上是一个 String => A,对于大小写 类 的 A,其类型为CellDecoder.

为此,我需要要求:

即:

implicit def caseClassCellDecoder[A, R, H](implicit
  gen: Generic.Aux[A, R],
  ev: R <:< (H :: HNil),
  d: CellDecoder[H]
): CellDecoder[A] = ???

我遇到的问题是,一旦我通过相关 CellDecoder 实例将 String 转换为 H,我就有点卡住了:ev 允许我将 R 转换为 H :: HNil,但不能将 H :: HNil 转换为 R。没有 R,我无法使用我的 Generic.Aux[A, R] 获得最终的 A 实例。

事实证明,将我的 H :: HNil 转换为 R 是可行的,但我不确定为什么,也无法说服自己永远如此。

我考虑过要求 R 严格等于 H :: HNil(即有一个 R =:= HNil),但是隐式无法解析。

有没有办法做我想做的事?

我确实使用了 =:= 而不是 <:< 但是交换了 RH::HNil 的边,这似乎有效:

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))
)

所以我能够按如下方式使用它:

case class TestDecoder(test: String)

def doDecode[A: CellDecoder](str: String): A = {
  implicitly[CellDecoder[A]].decode(str)
}

doDecode[TestDecoder]("encoded value")