在无形类型类方法中实现递归调用的正确方法是什么?
(一个早期的警告:我正在学习无形状,所以可能有一些明显的答案/替代方案,我还不知道。非常感谢您的帮助!)
我有一个类型类,它将case类转换为其他对象的嵌套结构-类似于this stackoverflow question-except中提到的ToMapRec示例,它返回由潜在递归成员组成的case类,而不是返回潜在递归映射。因此,不是转换MyType的实例
trait GetsConverted
case class MyType(someData: String, one: GetsConverted, other: GetsConverted) extends GetsConverted
case class MyOtherType(blah: AndSoOn) extends GetsConverted
case class AndSoOn(eventualFinalValue: Int)到一个可能的递归/嵌套的Map[String,Any]中(就像在另一个问题中一样),它返回类似于以下内容的实例:
case class ReturnType(name: String, data: Option[Any], more: Set[ReturnType])要创建more成员,似乎需要在类型类中进行递归调用。但是在另一个方法中调用类型类的转换方法需要将该函数中所有类型的隐式参数线程化到最外层的调用中。因此,不是像下面这样的类型类转换:
implicit def hconsToMapRec0[K, V, A <: HList, B <: HList](implicit
wit: Witness.Aux[K],
gen: LabelledGeneric.Aux[V, R],
tmrH: Lazy[ToMapRec[A]],
tmrT: Lazy[ToMapRec[B]]
): ReturnType = ???深度3方法(我猜)需要一个函数签名,如下所示:
implicit def hconsToMapRec0[K, V, A <: HList, B <: HList, W, C <: HList, D <: HList, X, E <: HList, F <: HList](implicit
wit: Witness.Aux[K],
gen0: LabelledGeneric.Aux[V, A],
tmrH0: Lazy[ToMapRec[A]],
tmrT0: Lazy[ToMapRec[B]],
gen1: LabelledGeneric.Aux[W, C],
tmrH1: Lazy[ToMapRec[C]],
tmrT1: Lazy[ToMapRec[D]],
gen2: LabelledGeneric.Aux[X, E],
tmrH2: Lazy[ToMapRec[E]],
tmrT2: Lazy[ToMapRec[F]]
): ReturnType = ???或者更糟。通常,这种方法需要一个方法,该方法在这种递归中将其隐式参数乘以相同级别的深度。并且深度级别的数量仅在运行时才知道。所以这不可能是实现这一目标的方法。
这感觉类似于scala集合库中硬编码的22位方法。由于Shapeless的存在理由是抽象而不是具体化,这似乎是一个需要更多Shapeless foo的问题,这是我到目前为止学到的。
所以问题是:如何编写一个无形状的类型类来将结构类似于上面的MyType示例的任意case类转换为像这样的递归定义的值:
ReturnType("MyType", Some("someData"), Set(
ReturnType("MyOtherType", None, Set(
ReturnType("AndSoOn", Some(10), Set())
)),
ReturnType("MyOtherType", None, Set(
ReturnType("AndSoOn", Some(20), Set())
))
))发布于 2017-01-25 08:08:13
通过下面的实现,我成功地获得了与您的示例很接近的东西。其中大部分都与this问题的答案类似。不同之处在于它会转换为ReturnType,并且我还为Coproduct案例(这是sealed trait的通用表示)添加了一些案例。
因此,使用以下代码:
val gen = LabelledGeneric[GetsConverted]
val m = MyType("someData", MyOtherType(AndSoOn(10)), MyOtherType(AndSoOn(20)))
val tmr = ToReturnTypeRec[gen.Repr]
val returnType = tmpr(gen.to(m))你会得到结果
ReturnType(MyType,Some(someData),Set(
ReturnType(MyOtherType,None,Set(
ReturnType(,Some(20),Set())
)),
ReturnType(MyOtherType,None,Set(
ReturnType(,Some(10),Set())
))
))具体实现如下:
trait ToReturnTypeRec[L] { def apply(l: L): ReturnType }
trait LowPriorityToReturnTypeRec {
implicit def hconsToReturnTypeRec1[K <: Symbol, V, T <: HList](implicit
wit: Witness.Aux[K],
tmrT: ToReturnTypeRec[T]
): ToReturnTypeRec[FieldType[K, V] :: T] = new ToReturnTypeRec[FieldType[K, V] :: T] {
def apply(l: FieldType[K, V] :: T): ReturnType =
tmrT(l.tail) match {
case ReturnType(n,d,m) => ReturnType("", Some(l.head), m)
}
}
}
object ToReturnTypeRec extends LowPriorityToReturnTypeRec {
def apply[T](implicit tmr: ToReturnTypeRec[T]) = tmr
implicit val hnilToReturnTypeRec: ToReturnTypeRec[HNil] = new ToReturnTypeRec[HNil] {
def apply(l: HNil): ReturnType = ReturnType("", None, Set())
}
implicit def hconsToReturnTypeRec0[K <: Symbol, V, T <: HList, R](implicit
// wit: Witness.Aux[K],
gen: LabelledGeneric.Aux[V, R],
tmrH: Lazy[ToReturnTypeRec[R]],
tmrT: ToReturnTypeRec[T]
): ToReturnTypeRec[FieldType[K, V] :: T] = new ToReturnTypeRec[FieldType[K, V] :: T] {
def apply(l: FieldType[K, V] :: T): ReturnType =
tmrT(l.tail) match {
case ReturnType(n,d,m) => ReturnType(n, d, m + tmrH.value(gen.to(l.head)))
}
}
implicit val cnillToReturnTypeRec: ToReturnTypeRec[CNil] = new ToReturnTypeRec[CNil] {
def apply(c: CNil): ReturnType = ReturnType("Impossible", None, Set())
}
implicit def cconsToReturnTypeRec0[K <: Symbol, V <: Product, T <: Coproduct](implicit
wit: Witness.Aux[K],
tmrH: Lazy[ToReturnTypeRec[V]],
tmrT: Lazy[ToReturnTypeRec[T]]
): ToReturnTypeRec[FieldType[K,V] :+: T] = new ToReturnTypeRec[FieldType[K, V] :+: T] {
def apply(c: FieldType[K,V] :+: T): ReturnType = {
c match {
case Inl(h) => tmrH.value(h) match {
case ReturnType(_,d,m) => ReturnType(wit.value.name, d, m)
}
case Inr(t) => tmrT.value(t)
}
}
}
implicit def genericToReturnTypeRec[P, R]( implicit
gen: LabelledGeneric.Aux[P, R],
tmr: Lazy[ToReturnTypeRec[R]]
): ToReturnTypeRec[P] = new ToReturnTypeRec[P] {
def apply(p: P): ReturnType = tmr.value(gen.to(p))
}
}https://stackoverflow.com/questions/41626099
复制相似问题