I have looked at the cool solution presented by Travis Brown which allows converting case classes between each other in a generic way. I tried to use it to convert HList
to a case class
but did not managed to get it worked. Here is my attempt:
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)
}
Unfortunately it fails with the error:
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)
Is there a way to enhance the converTo[B]
function so it can convert between HList
s as well?
Shapeless's Generic
and LabelledGeneric
are type classes that provide a generic representation for case classes and sealed trait hierarchies using hlists and coproducts. If you already have an hlist, you don't really need a Generic
instance, and Shapeless doesn't provide one. In your case this means you can actually skip the genS
and SR
parts:
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)
}
This will give you SomeProductType(4,4,ssdf,true,2,4)
, as you'd expect.
Note that I've changed genT
from LabelledGeneric
to Generic
, since we no longer have labels to align on the input side. I guess you could add some extra machinery to "inject" the unlabeled input into a Shapeless record to match the LabelledGeneric
type, but in this specific use case at least there's not really any point.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.