Бесформенные линзы странного поведения
Я пытаюсь преобразовать свой класс дела в последовательность, содержащую линзу для каждого поля. Я создал следующий упрощенный пример, чтобы выделить проблему, с которой я столкнулся.
Следующий код выдаст ошибку времени выполнения:
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)
Фактическая ошибка гласит "Выражение, которое я не оцениваю к неотрицательному литералу Int".
Я чувствую, что это сообщение об ошибке вводит в заблуждение, так как код val lens3 = lens[Testing] >> 2 (то есть доступ к одному полю слишком много) выдаст то же сообщение об ошибке.
Кто-нибудь испытывал подобное поведение в бесформенном? И есть ли более простой способ выделить элементные линзы для каждого поля в моем классе дел в последовательность (т. Е. Не как @lenses в монокле, где вам все еще нужно получить доступ к каждому объективу, используя имя поля)?
1 ответ
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)
имеет тип Seq[Nat]
, так i
имеет тип Nat
(а не конкретный 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