递归 Poly1 以递归类型参数

Recursive Poly1 to recurse over type parameters

我正在使用来自 shapeless 的 Poly1 从实例构建案例 类(描述它们的序列化)的方案。构建

Schema
case class A(b: B, c: String, d: List[Int], e: Option[List[Option[Int]]])

每个包含的类型都需要一个架构。

一个 Schema 对象拥有(除其他外)其成员的示例值。我从所有 primitive 类型(IntFloatString、...)的实例中提取这些示例值,这些类型的方案构建于飞过我的 Poly1。所有 complex 类型(我指的是具有其他成员值的自定义类型)都被引用,因为它们也可能具有自定义序列化方法。这很容易通过要求模式出现在隐式范围内来解决。

现在知道如何为任何列表(或任何其他集合)构造 Schema iff​​ 类型参数有一个 Schema (s).这与其他 monad 类型相同,例如 Option.

Poly1 的想法是将成员类型映射到它们的方案,这些方案要么即时构建,要么从隐式范围查找。这需要我为所有原始类型以及所有必要的单子定义一个案例。这种方法通常有效,但有很多样板。

当前 Poly1 对象(NGSchema 是一个 trait,所有 Schema[T] 实例继承,ref[T] 查找 Schema[T] 的实例从隐式作用域和函数 integerlongfloat 构造一个给定示例的 Schema[T]

private object typeRecursion extends Poly1 {
    implicit val caseInt      = at[Int]     [NGSchema](integer(_))
    implicit val caseLong     = at[Long]    [NGSchema](long(_))
    implicit val caseFloat    = at[Float]   [NGSchema](float(_))

    ...

    implicit def caseOption[T: Schema](implicit c: Case.Aux[T, NGSchema]) = at[Option[T]][NGSchema]{
      case Some(v) => OptionSchema(typeRecursion(v)(c))
      case None => OptionSchema(ref[T])
    }
    implicit def caseList[T: Schema](implicit c: Case.Aux[T, NGSchema]) = at[List[T]][NGSchema]{
      case v :: tl => SeqSchema(typeRecursion(v)(c))
      case Nil => SeqSchema(ref[T])
    }

    ...

    implicit def caseElse[T: Schema] = at[T][NGSchema]{
      case _ => ref[T]
    }
  }

但是在成员 e 的情况下,这会失败,因为 Option[List[Option[Int]]] 的模式不会出现在隐式范围中,因为它应该动态构建。我相信我的 Poly1 应该是递归的,可以很好地解决这个问题。然而,这留下了一个问题,即 Option 案例确实需要某种类型绑定的最内部类型,这在递归的那个点是未知的 iff​​ 这是一个复杂的类型,因为这不能即时构建。

我希望函数将 Option[List[Option[Int]]] 映射到 OptionSchema(SeqSchema(OptionSchema(integer(example))Option[B] 应该从隐式范围查找 Schema[B] 并执行 OptionSchema(ref[B]).

这是解决问题的正确方法吗?

Poly1 本身不是 implicit,只有大小写是隐含的。我认为您混淆了类型级别和价值级别。我会将隐式 Schema 实例的提供与实际操作它们的函数分开(这可能只是一个普通函数?):

implicit object IntSchema extends NGSchema[Int]{ ... }
implicit def optionSchema[T: Schema] = new Schema[Option[T]]{...}
...
def myFunction[T: Schema](t: T) = ... //or Poly with cases here if you need it.