gpt4 book ai didi

scala - 如何定义一个 HList 类型,但基于另一个 HList 类型

转载 作者:行者123 更新时间:2023-12-04 08:27:14 29 4
gpt4 key购买 nike

假设我有一个案例类:

case class Foo(num: Int, str: String, bool: Boolean)
现在我还有一个简单的包装器:
sealed trait Wrapper[T]
case class Wrapped[T](value: T) extends Wrapper[T]
(以及其他一些在这里不重要的 Wrapper 实现)
我可以使用 Generic[Foo] 来获取代表这个案例类的 Aux: val genFoo = Generic[Foo](在我的真实代码中,我使用 LabelledGeneric 以免丢失字段名称)
这为我提供了一个表示 HList 定义的类型:
Generic.Aux[Foo, Int :: String :: Boolean :: HNil]
(当与 LabelledGeneric 一起使用时,定义要复杂得多,但本质上是一样的)
现在我想为 HList 创建一个类型定义,而不是原始类型,而是包含包装类型。例子:
type WrappedHlist = Wrapper[Int] :: Wrapper[String] :: Wrapper[Boolean] :: HNil
然后我可以使用这个类型定义来生成一个 Circe 编码器/解码器(我已经为 Wrapper 类型提供了必要的编码器/解码器)。
所有必要的信息都在编译时存在,因为第二个 HList 的定义很容易从第一个确定。现在,我可以通过手动写出定义来实现这一点,或者通过使用冗余版本重复案例类 Foo 的定义,其中所有内容都定义为 Wrappers。如何创建不需要我重复所有内容的定义?

最佳答案

嗯,这可以通过一些类型类、依赖路径的类型和 Aux 模式来实现:

trait WrapperHelper[In] {
type Out
def wrap(i: In): Out
}
object WrapperHelper {
type Aux[I, O] = WrapperHelper[I] { type Out = O }

implicit val nilWH: WrapperHelper.Aux[HNil, HNil] = new WrapperHelper[HNil] {
type Out = HNil
def wrap(i: HNil): HNil = i
}

implicit def hconsWH[H, TI <: HList, TO <: HList](
implicit
tailWH: WrapperHelper.Aux[TI, TO]
): WrapperHelper.Aux[H :: TI, Wrapper[H] :: TO] = new WrapperHelper[H :: TI] {
type Out = Wrapper[H] :: TO
def wrap(i: H :: TI): Wrapper[H] :: TO = i match {
case head :: tail => Wrapped(head) :: tailWH.wrap(tail)
}
}
}

def wrap[I](i: I)(implicit wh: WrapperHelper[I]): wh.Out = wh.wrap(i)
HNIl 被视为一种特殊情况,其中 In = Out。对于其他一切……您仍然必须递归地映射类型。虽然不漂亮,但这应该做你想做的:
@ wrap(Generic[Foo].to(Foo(1, "", true)))
res7: Wrapper[Int] :: Wrapper[String] :: Wrapper[Boolean] :: HNil = Wrapped(1) :: Wrapped("") :: Wrapped(true) :: HNil
假设您想提供一些自定义编码/解码逻辑,您应该修改签名
implicit def hconsWH[H, TI <: HList, TO <: HList](
implicit
tailWH: WrapperHelper.Aux[TI, TO]
): WrapperHelper.Aux[H :: TI, Wrapper[H] :: TO]
implicit def hconsWH[H, TI <: HList, TO <: HList](
implicit
thatThingINeedToLiftAToWrapperA: Encoder[A], // whatever is needed to lift A => Wrapper[A]
tailWH: WrapperHelper.Aux[TI, TO]
): WrapperHelper.Aux[H :: TI, Wrapper[H] :: TO]
即使您不需要实现,在这里定义 typeclass 仍然很有用,只是为了提供一些可以为您解析类型的隐式证据。

关于scala - 如何定义一个 HList 类型,但基于另一个 HList 类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65201029/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com