0

我正在尝试将我的案例类转换为包含每个字段的镜头的序列。我创建了以下简化示例来突出我遇到的问题。

以下代码将给出运行时错误:

import shapeless._

case class Testing(field1: String, field2: Double)

val lenses = Seq(0,1).map(i => lens[Testing] >> i)

而以下不是:

import shapeless._

case class Testing(field1: String, field2: Double)

val lens1 = lens[Testing] >> 0
val lens2 = lens[Testing] >> 1

val lenses = Seq(lens1, lens2)

实际错误为“表达式 i 不计算为非负 Int 文字”。

我觉得这个错误消息具有误导性,因为代码 val lens3 = lens[Testing] >> 2 (即访问一个字段太多)会给出相同的错误消息。

有没有人在无形中经历过这样的行为?是否有一种更简单的方法可以将我的案例类中每个字段的元素镜头提取到一个序列中(即不像单片眼镜中的@lenses,您仍然需要使用字段名称访问每个镜头)?

4

1 回答 1

0
lens[Testing] >> 0
lens[Testing] >> 1

被隐式转换为

lens[Testing] >> Nat._0
lens[Testing] >> Nat._1

这有效但是

val lenses = Seq(0,1).map(i => lens[Testing] >> i)

或者val lenses = Seq(Nat._0,Nat._1).map(i => lens[Testing] >> i)没有。

Seq(Nat._0,Nat._1)有 type Seq[Nat],所以i有 type Nat(而不是 specific Nat._0, Nat._1),这太粗糙了。

以下构造HList镜头(而不是Seq)的方法似乎有效:

  import shapeless.{::, Generic, HList, HNil, Lens, MkHListSelectLens}

  case class Testing(field1: String, field2: Double)

  trait MkLensHlist[A] {
    type Out <: HList
    def apply(): Out
  }

  object MkLensHlist {
    type Aux[A, Out0 <: HList] = MkLensHlist[A] { type Out = Out0 }
    def instance[L, Out0 <: HList](x: Out0): Aux[L, Out0] = new MkLensHlist[L] {
      override type Out = Out0
      override def apply(): Out0 = x
    }

    def apply[A](implicit instance: MkLensHlist[A]): instance.Out = instance()

    implicit def mk[A, L <: HList, Out <: HList](implicit
                                                 gen: Generic.Aux[A, L],
                                                 apply: ApplyMkHListSelectLens.Aux[L, Out]
                                                ): Aux[A, Out] = instance(apply())
  }

  trait ApplyMkHListSelectLens[L <: HList] {
    type Out <: HList
    def apply(): Out
  }

  object ApplyMkHListSelectLens {
    type Aux[L <: HList, Out0 <: HList] = ApplyMkHListSelectLens[L] { type Out = Out0}
    def instance[L <: HList, Out0 <: HList](x: Out0): Aux[L, Out0] = new ApplyMkHListSelectLens[L] {
      override type Out = Out0
      override def apply(): Out0 = x
    }

    implicit def mk[L <: HList, Out <: HList](implicit
                                              apply: ApplyMkHListSelectLens1.Aux[L, L, Out]
                                             ): Aux[L, Out] =
      instance(apply())
  }


  trait ApplyMkHListSelectLens1[L <: HList, L1 <: HList] {
    type Out <: HList
    def apply(): Out
  }

  object ApplyMkHListSelectLens1 {
    type Aux[L <: HList, L1 <: HList, Out0 <: HList] = ApplyMkHListSelectLens1[L, L1] { type Out = Out0}
    def instance[L <: HList, L1 <: HList, Out0 <: HList](x: Out0): Aux[L, L1, Out0] = new ApplyMkHListSelectLens1[L, L1] {
      override type Out = Out0
      override def apply(): Out0 = x
    }

    implicit def mk1[L <: HList, H, T <: HList, Out <: HList](implicit
                                                             lens: MkHListSelectLens[L, H],
                                                             apply: Aux[L, T, Out]
                                                            ): Aux[L, H :: T, Lens[L, H] :: Out] =
      instance(lens() :: apply())

    implicit def mk2[L <: HList]: Aux[L, HNil, HNil] =
      instance(HNil)
  }

  MkLensHlist[Testing] 
  // shapeless.MkHListSelectLens$$anon$36$$anon$17@340f438e :: shapeless.MkHListSelectLens$$anon$36$$anon$17@30c7da1e :: HNil
于 2018-04-16T18:23:27.197 回答