自动将 HList 转为 Record
Automatically transfer HList into a Record
我的目标是根据需要自动将 HList
转换为 Record
。
请注意,下面的代码是用 Scala 2.13 编写的,使用单例类型而不是 Symbol
s。
import shapeless._
import shapeless.record._
import shapeless.labelled._
type BestBeforeDate = Record.`"day" -> Option[Int], "month" -> Option[Int], "year" -> Int`.T
object PolyToField extends Poly1 {
implicit def mapA[A, K]: Case.Aux[A, FieldType[K, A]] = at[A](a => field[K][A](a))
}
val x: BestBeforeDate = (None :: None :: 12 :: HNil)
.map(PolyToField)
我收到这个错误:
type mismatch;
found : None.type with shapeless.labelled.KeyTag[Nothing,None.type] :: None.type with shapeless.labelled.KeyTag[Nothing,None.type] :: Int with shapeless.labelled.KeyTag[Nothing,Int] :: shapeless.HNil
required: emergencymanager.commons.data.package.BestBeforeDate
(which expands to) Option[Int] with shapeless.labelled.KeyTag[String("day"),Option[Int]] :: Option[Int] with shapeless.labelled.KeyTag[String("month"),Option[Int]] :: Int with shapeless.labelled.KeyTag[String("year"),Int] :: shapeless.HNil
似乎 Poly1
函数的第二个类型参数被推断为 Nothing
而不是我需要的。
我怎样才能做到这一点?
首先, 您应该使用类型归属指定 None
具有类型 Option[...]
(这就是为什么在 Cats there are none[...]
and .some
, see also 中,项目9).或者使用 Option.empty[...]
.
其次,你应该使用 rather than standard shapeless.ops.hlist.Mapper
trait MapperWithReturnType[HF, Out <: HList] extends Serializable {
type In <: HList
def apply(t: In): Out
}
object MapperWithReturnType {
type Aux[HF, Out <: HList, In0 <: HList] =
MapperWithReturnType[HF, Out] { type In = In0 }
def instance[HF, Out <: HList, In0 <: HList](f: In0 => Out): Aux[HF, Out, In0] =
new MapperWithReturnType[HF, Out] {
override type In = In0
override def apply(t: In0): Out = f(t)
}
implicit def hnilMapper[HF <: Poly]: Aux[HF, HNil, HNil] = instance(_ => HNil)
implicit def hconsMapper[HF <: Poly, InH, InT <: HList, OutH, OutT <: HList](implicit
hc : poly.Case1.Aux[HF, InH, OutH],
mt : Aux[HF, OutT, InT]
): Aux[HF, OutH :: OutT, InH :: InT] = instance(l => hc(l.head) :: mt(l.tail))
}
implicit final class HListOps[L <: HList](l : L) extends Serializable {
def mapWithReturnType[Out <: HList](f: Poly)(implicit
mapper: MapperWithReturnType.Aux[f.type, Out, L]
): Out = mapper(l)
}
val x = ((None: Option[Int]) :: (None: Option[Int]) :: 12 :: HNil)
.mapWithReturnType[BestBeforeDate](PolyToField)
// val x = (Option.empty[Int] :: Option.empty[Int] :: 12 :: HNil)
// .mapWithReturnType[BestBeforeDate](PolyToField)
x: BestBeforeDate
我的目标是根据需要自动将 HList
转换为 Record
。
请注意,下面的代码是用 Scala 2.13 编写的,使用单例类型而不是 Symbol
s。
import shapeless._
import shapeless.record._
import shapeless.labelled._
type BestBeforeDate = Record.`"day" -> Option[Int], "month" -> Option[Int], "year" -> Int`.T
object PolyToField extends Poly1 {
implicit def mapA[A, K]: Case.Aux[A, FieldType[K, A]] = at[A](a => field[K][A](a))
}
val x: BestBeforeDate = (None :: None :: 12 :: HNil)
.map(PolyToField)
我收到这个错误:
type mismatch;
found : None.type with shapeless.labelled.KeyTag[Nothing,None.type] :: None.type with shapeless.labelled.KeyTag[Nothing,None.type] :: Int with shapeless.labelled.KeyTag[Nothing,Int] :: shapeless.HNil
required: emergencymanager.commons.data.package.BestBeforeDate
(which expands to) Option[Int] with shapeless.labelled.KeyTag[String("day"),Option[Int]] :: Option[Int] with shapeless.labelled.KeyTag[String("month"),Option[Int]] :: Int with shapeless.labelled.KeyTag[String("year"),Int] :: shapeless.HNil
似乎 Poly1
函数的第二个类型参数被推断为 Nothing
而不是我需要的。
我怎样才能做到这一点?
首先, 您应该使用类型归属指定 None
具有类型 Option[...]
(这就是为什么在 Cats there are none[...]
and .some
, see also 中,项目9).或者使用 Option.empty[...]
.
其次,你应该使用
trait MapperWithReturnType[HF, Out <: HList] extends Serializable {
type In <: HList
def apply(t: In): Out
}
object MapperWithReturnType {
type Aux[HF, Out <: HList, In0 <: HList] =
MapperWithReturnType[HF, Out] { type In = In0 }
def instance[HF, Out <: HList, In0 <: HList](f: In0 => Out): Aux[HF, Out, In0] =
new MapperWithReturnType[HF, Out] {
override type In = In0
override def apply(t: In0): Out = f(t)
}
implicit def hnilMapper[HF <: Poly]: Aux[HF, HNil, HNil] = instance(_ => HNil)
implicit def hconsMapper[HF <: Poly, InH, InT <: HList, OutH, OutT <: HList](implicit
hc : poly.Case1.Aux[HF, InH, OutH],
mt : Aux[HF, OutT, InT]
): Aux[HF, OutH :: OutT, InH :: InT] = instance(l => hc(l.head) :: mt(l.tail))
}
implicit final class HListOps[L <: HList](l : L) extends Serializable {
def mapWithReturnType[Out <: HList](f: Poly)(implicit
mapper: MapperWithReturnType.Aux[f.type, Out, L]
): Out = mapper(l)
}
val x = ((None: Option[Int]) :: (None: Option[Int]) :: 12 :: HNil)
.mapWithReturnType[BestBeforeDate](PolyToField)
// val x = (Option.empty[Int] :: Option.empty[Int] :: 12 :: HNil)
// .mapWithReturnType[BestBeforeDate](PolyToField)
x: BestBeforeDate