有没有办法以通用方式将 Hlist 转换为适当的案例类?

Som*_*ame 4 functional-programming scala hlist shapeless

我看过Travis Brown 提出的很酷的解决方案,它允许以通用方式在彼此之间转换案例类。我试图用它来转换HList为 acase class但没有设法让它工作。这是我的尝试:

import shapeless._, ops.hlist.Align
import syntax.std.tuple._

object Shplss  extends App {
  class SameFieldsConverter[T] {
    def apply[S, SR <: HList, TR <: HList](s: S)(implicit
                                                 genS: LabelledGeneric.Aux[S, SR],
                                                 genT: LabelledGeneric.Aux[T, TR],
                                                 align: Align[SR, TR]
    ) = genT.from(align(genS.to(s)))
  }

  def convertTo[T] = new SameFieldsConverter[T]

  type SomeType = Int :: Int :: String :: Boolean :: Int :: Int :: HNil
  final case class SomeProductType(f1: Int, f2: Int, f3: String, f4: Boolean, f5: Int, f6: Int)

  val some: SomeType = (4, 4, "ssdf", true, 2, 4).productElements

  convertTo[SomeProductType](some)
}
Run Code Online (Sandbox Code Playgroud)

不幸的是它失败并出现错误:

Error:(22, 29) could not find implicit value for parameter genS: shapeless.LabelledGeneric.Aux[com.test.Shplss.SomeType,SR]
  convertTo[SomeProductType](some)


Error:(22, 29) not enough arguments for method apply: (implicit genS: shapeless.LabelledGeneric.Aux[com.test.Shplss.SomeType,SR], implicit genT: shapeless.LabelledGeneric.Aux[com.test.Shplss.SomeProductType,TR], implicit align: shapeless.ops.hlist.Align[SR,TR])com.test.Shplss.SomeProductType in class SameFieldsConverter.
Unspecified value parameters genS, genT, align.
  convertTo[SomeProductType](some)
Run Code Online (Sandbox Code Playgroud)

有没有办法增强该converTo[B]功能,使其也可以在HLists之间进行转换?

Tra*_*own 5

ShapelessGenericLabelledGeneric是使用 hlists 和 coproducts 为案例类和密封特征层次结构提供通用表示的类型类。如果您已经有一个 hlist,那么您实际上并不需要一个Generic实例,Shapeless 不提供实例。在您的情况下,这意味着您实际上可以跳过genSSR部分:

import shapeless._, ops.hlist.Align
import syntax.std.tuple._

object Shplss  extends App {
  class SameFieldsConverter[T] {
    def apply[S <: HList, TR <: HList](s: S)(implicit
      genT: Generic.Aux[T, TR],
      align: Align[S, TR]
    ) = genT.from(align(s))
  }

  def convertTo[T] = new SameFieldsConverter[T]

  type SomeType = Int :: Int :: String :: Boolean :: Int :: Int :: HNil
  final case class SomeProductType(f1: Int, f2: Int, f3: String, f4: Boolean, f5: Int, f6: Int)

  val some: SomeType = (4, 4, "ssdf", true, 2, 4).productElements

  convertTo[SomeProductType](some)
}
Run Code Online (Sandbox Code Playgroud)

这会给你SomeProductType(4,4,ssdf,true,2,4),正如你所期望的。

请注意,我genT已从更改LabelledGenericGeneric,因为我们不再有要在输入端对齐的标签。我想您可以添加一些额外的机制来将未标记的输入“注入”到 Shapeless 记录中以匹配LabelledGeneric类型,但至少在这个特定用例中,至少没有任何意义。