Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 将Hlist[F[a]]转换为F[B],其中case类B的类型与a对齐_Scala_Typeclass_Shapeless_Fixed Width_Scodec - Fatal编程技术网

Scala 将Hlist[F[a]]转换为F[B],其中case类B的类型与a对齐

Scala 将Hlist[F[a]]转换为F[B],其中case类B的类型与a对齐,scala,typeclass,shapeless,fixed-width,scodec,Scala,Typeclass,Shapeless,Fixed Width,Scodec,注意:我正在学习shapeless,如果我遗漏了任何细节,请要求澄清 背景: 我正在为固定长度格式构建编码/解码解决方案,同时练习Shapess。其思想是,每个case类都有自己的编码器/解码器,定义为与其属性一致的HList 即使两个类共享相同的属性,它们的编码也可能不同。每个字段的描述将包含一些(4)值。但这在问题中并不重要 问题: 此处提供完整代码: 我声明了一个示例case类及其编码器: case class Employee(name: String, number: Int, man

注意:我正在学习shapeless,如果我遗漏了任何细节,请要求澄清

背景: 我正在为固定长度格式构建编码/解码解决方案,同时练习Shapess。其思想是,每个
case类
都有自己的编码器/解码器,定义为与其属性一致的
HList

即使两个类共享相同的属性,它们的编码也可能不同。每个字段的描述将包含一些(4)值。但这在问题中并不重要

问题: 此处提供完整代码:

我声明了一个示例case类及其编码器:

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]]]]
现在,encoder
隐式地
正在寻找一个
FLEncoder[Employee]
,我希望它可以是上面的实现

我使用此解决方案组合元组的TypeClass:

但我得到了:

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)
问题: 因此,基本上,如何使用
无形状
,以便知道此
Hlist
是对齐的
案例类
的编码器类型


类似的问题在scodec中得到解决。如果您在此处查看演示:

您可以进行这样的转换:

case class Person(name: String, age: Int)

val pc: Codec[shapeless.::[String, shapeless.::[Int, HNil]]] = (("name" | fixed(10, '_')) :: ("age" | fixed(6, '0').narrow[Int](strToInt, _.toString)))

val personCodec: Codec[Person] = pc.as[Person]

但我不知道如何在我的情况下使用。

您需要的是提供一种方法,告诉编译器您的
FLEncoder
列表可以转换为
FLEncoder
列表。由于我们处于类型级别,这可以通过typeclass完成:

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))
  }
}
现在,所有隐式都应该在
Main
的范围内


顺便说一句,由于您使用
HList
定义了FLEncoder,因此不再需要
ProductTypeClassCompanion
,因为这只是从基本情况进行推断。

您能给我们介绍一下特性
FLEncoder[T]
,以便更好地理解您想要实现的目标吗?同时,看一看,这里给出了一个完整的示例(在我的解决方案中是其中的一部分)。编码器在GitHub上的
Main.scala中被关闭。我添加了您的对象并导入了隐式,但仍然得到相同的错误。你能用我的
Main.scala
给出一个有效的解决方案吗?你仍然缺少的是通用转换(从你的
HList
Employee
)。我会通知你并把更新后的答案放在这里。你知道为什么编译器不知道我正在生成的Hlist与shapess将创建的Hlist不相等吗?为什么它没有发现它是一个隐式的值呢?Shapess从来不会产生一个
F[a]::F[B]::HNil
,而是一个
F[a::B::HNil]
,当你思考它时,这是完全不同的。
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]