Есть ли способ преобразовать Hlist в соответствующий класс case в общем c способом? - PullRequest
4 голосов
/ 29 мая 2020

Я рассмотрел классное решение , представленное Трэвисом Брауном, которое позволяет преобразовывать классы case друг в друга в общем виде c. Я попытался использовать его для преобразования HList в case 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)
}

К сожалению, это не удается с ошибкой:

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)

Есть ли способ улучшить функцию converTo[B], чтобы она могла конвертировать между HList s тоже?

1 Ответ

5 голосов
/ 29 мая 2020
Generic и LabelledGeneric

Shapeless - это классы типов, которые обеспечивают общее c представление для классов case и запечатанных иерархий признаков с использованием списков hlists и копродукций. Если у вас уже есть hlist, вам действительно не нужен экземпляр Generic, а Shapeless его не предоставляет. В вашем случае это означает, что вы можете пропустить части genS и SR:

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

Это даст вам SomeProductType(4,4,ssdf,true,2,4), как и следовало ожидать.

Обратите внимание, что Я изменил genT с LabelledGeneric на Generic, так как у нас больше нет меток для выравнивания на стороне ввода. Я предполагаю, что вы могли бы добавить дополнительные механизмы для «вставки» немаркированного ввода в запись Shapeless, чтобы соответствовать типу LabelledGeneric, но в этом конкретном варианте использования c по крайней мере нет никакого смысла.

...