注意:我正在学习无形,所以如果我遗漏任何细节,请要求澄清。
我正在构建一个固定长度格式的编码/解码解决方案,同时练习无形。我们的想法是每个^(?!.*\.result.med$).*\.med$
都有自己的编码器/解码器,定义为与其属性对齐的case class
。
即使两个类共享相同的属性,它们的编码也可能不同。每个字段的描述将包含一些(4)值。但这在问题上并不重要。
我声明了一个示例案例类及其编码器:
HList
所以case class Employee(name: String, number: Int, manager: Boolean)
object Employee {
implicit val employeeEncoder =
FLEncoder.fixed((s: String) => s) ::
FLEncoder.fixed((s: String) => s) ::
FLEncoder.fixed((s: Int) => s.toString) ::
FLEncoder.fixed((s: Boolean) => s.toString) ::
HNil
}
的类型很漂亮:
employeeEncoder
现在,编码器::[FLEncoder[String], ::[FLEncoder[String], ::[FLEncoder[Int], ::[FLEncoder[Boolean], HNil]]]]
正在寻找implicitly
,我希望这可能是上述实现。
我已经使用此解决方案将TypeClasses组合为元组:
但我得到了:
FLEncoder[Employee]
如果我单独声明这些编码器,它们工作正常
Error:(69, 17) could not find implicit value for parameter enc: test.FLEncoder[test.Employee]
println(encode(example))
基本上,如何使用implicit val a = fixed((s: String) => s)
implicit val b = fixed((s: Int) => s.toString)
implicit val c = fixed((s: Boolean) => s.toString)
,以便知道此Shapeless
是对齐Hlist
的编码器类型?
在scodec 中解决了类似的问题。如果您在此处查看演示: https://github.com/atais/Fixed-Length/blob/03b395947a6b00e548ea1e76a9660e471f136565/src/main/scala/test/Fixed.scala
你可以做这样的转变:
case class
但我不知道如何在我的案例中使用TransformSyntax.as。
答案 0 :(得分:2)
您需要的是告诉编译器您的FLEncoder
列表可以转换为FLEncoder
列表。由于我们处于类型级别,因此可以使用类型类来完成:
trait ListOfEncoder[L <: HList] {
type Inside <: HList
def merge(l: L): FLEncoder[Inside]
}
object ListOfEncoder {
type Aux[L <: HList, I <: HList] = ListOfEncoder[L] { type Inside = I }
implicit val hnil: Aux[HNil, HNil] = new ListOfEncoder[HNil] {
type Inside = HNil
def merge(l: HNil) = FLEncoder.fixed(_ => "")
}
implicit def hcons[H, T <: HList](implicit T: ListOfEncoder[T]): Aux[FLEncoder[H] :: T, H :: T.Inside] = new ListOfEncoder[FLEncoder[H] :: T] {
type Inside = H :: T.Inside
def merge(l: FLEncoder[H] :: T): FLEncoder[H :: T.Inside] =
FLEncoder.fixed((ht: H :: T.Inside) => l.head.encode(ht.head) + T.merge(l.tail).encode(ht.tail))
}
}
现在,在你的`FLEncoder对象中,添加这个隐式类:
implicit class EncoderAsGeneric[L <: HList, I <: HList](l: L)(implicit L: ListOfEncoder.Aux[L, I]) {
def as[E](implicit gen: Generic.Aux[E, I]) =
FLEncoder.fixed((e: E) => L.merge(l).encode(gen.to(e))
}
这将允许您定义
implicit val employeeEncoder = (fixed((s: String) => s) ::
fixed((s: String) => s) ::
fixed((s: Int) => s.toString) ::
fixed((s: Boolean) => s.toString) ::
HNil).as[Employee]
现在,所有隐含都应该在Main
范围内。
顺便说一句,由于您使用HList
定义了FLEncoder,因此不再需要ProductTypeClassCompanion
,因为这仅适用于基本情况的推断。