【问题标题】:Deriving type class instances for case classes with exactly one field为只有一个字段的案例类派生类型类实例
【发布时间】:2015-11-06 09:09:47
【问题描述】:

我正在开发一个 CSV 解析库 (tabulate)。它使用简单的类型类进行编码/解码:例如,编码是通过CellEncoder(对单个单元格进行编码)和RowEncoder(对整行进行编码)的实例完成的。

使用 shapeless,我发现自动派生以下类型类实例非常简单:

  • RowEncoder[A] 如果A 是其字段都具有CellEncoder 的案例类。
  • RowEncoder[A] 如果A 是一个ADT,其替代品都有RowEncoder
  • CellEncoder[A] 如果A 是一个ADT,其替代品都有CellEncoder

问题是,最后一个在现实生活中几乎完全没用:ADT 的替代方案几乎总是案例类,我无法为具有多个字段的案例类派生CellEncoder

然而,我希望能够为具有单个字段且类型为CellEncoder 的案例类派生一个CellEncoder。例如,Either、scalaz 的 \/、猫的 Xor...

这是我目前所拥有的:

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

我错过了什么吗?我正在尝试做的事情是否可能?

【问题讨论】:

    标签: scala shapeless


    【解决方案1】:

    正确推断 H 有点棘手,但您可以使用 &lt;:&lt; 实例来做到这一点:

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

    (为了一个完整的工作示例,我编造了一个简单的CellEncoder。)

    这是因为可以在编译器查找 Generic.Aux[A, R] 实例时推断出 R,然后可以在查找 ev 的值时指导推断 H

    【讨论】:

    • 我需要仔细考虑这个问题,但我可以确认它有效。巧合的是,我一直在 Circe 的代码中花费大量时间来理解 case 类的自动类型类派生,所以感谢 Circe 的回答!
    • 我正在努力解决这个问题的双重性 - 写一个 CellDecoder (String =&gt; A),因为 R &lt;:&lt; H :: HNil 在这种情况下没有帮助:子类型关系走错了路,我有一个H :: HNil,需要一个R。这是什么礼仪,我应该打开一个新问题,修改这个问题,...?
    • @NicolasRinaudo 可以提出一个新问题。
    • 完成,新问题是here
    猜你喜欢
    • 2013-01-23
    • 2021-11-19
    • 2017-04-22
    • 1970-01-01
    • 1970-01-01
    • 2011-12-25
    • 2016-09-17
    • 1970-01-01
    • 2011-06-06
    相关资源
    最近更新 更多