首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Shapeless:类型类中的递归调用

Shapeless:类型类中的递归调用
EN

Stack Overflow用户
提问于 2017-01-13 09:39:03
回答 1查看 454关注 0票数 2

在无形类型类方法中实现递归调用的正确方法是什么?

(一个早期的警告:我正在学习无形状,所以可能有一些明显的答案/替代方案,我还不知道。非常感谢您的帮助!)

我有一个类型类,它将case类转换为其他对象的嵌套结构-类似于this stackoverflow question-except中提到的ToMapRec示例,它返回由潜在递归成员组成的case类,而不是返回潜在递归映射。因此,不是转换MyType的实例

代码语言:javascript
复制
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]中(就像在另一个问题中一样),它返回类似于以下内容的实例:

代码语言:javascript
复制
case class ReturnType(name: String, data: Option[Any], more: Set[ReturnType])

要创建more成员,似乎需要在类型类中进行递归调用。但是在另一个方法中调用类型类的转换方法需要将该函数中所有类型的隐式参数线程化到最外层的调用中。因此,不是像下面这样的类型类转换:

代码语言:javascript
复制
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方法(我猜)需要一个函数签名,如下所示:

代码语言:javascript
复制
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类转换为像这样的递归定义的值:

代码语言:javascript
复制
ReturnType("MyType", Some("someData"), Set(
  ReturnType("MyOtherType", None, Set(
    ReturnType("AndSoOn", Some(10), Set())
  )), 
  ReturnType("MyOtherType", None, Set(
    ReturnType("AndSoOn", Some(20), Set())
  ))
))
EN

回答 1

Stack Overflow用户

发布于 2017-01-25 08:08:13

通过下面的实现,我成功地获得了与您的示例很接近的东西。其中大部分都与this问题的答案类似。不同之处在于它会转换为ReturnType,并且我还为Coproduct案例(这是sealed trait的通用表示)添加了一些案例。

因此,使用以下代码:

代码语言:javascript
复制
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))

你会得到结果

代码语言:javascript
复制
ReturnType(MyType,Some(someData),Set(
     ReturnType(MyOtherType,None,Set(
         ReturnType(,Some(20),Set())
     )),
     ReturnType(MyOtherType,None,Set(
         ReturnType(,Some(10),Set())
     ))
))

具体实现如下:

代码语言:javascript
复制
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))
  }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41626099

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档