递归 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 类型(Int
、Float
、String
、...)的实例中提取这些示例值,这些类型的方案构建于飞过我的 Poly1
。所有 complex 类型(我指的是具有其他成员值的自定义类型)都被引用,因为它们也可能具有自定义序列化方法。这很容易通过要求模式出现在隐式范围内来解决。
现在知道如何为任何列表(或任何其他集合)构造 Schema
iff 类型参数有一个 Schema
(s).这与其他 monad 类型相同,例如 Option
.
Poly1
的想法是将成员类型映射到它们的方案,这些方案要么即时构建,要么从隐式范围查找。这需要我为所有原始类型以及所有必要的单子定义一个案例。这种方法通常有效,但有很多样板。
当前 Poly1
对象(NGSchema
是一个 trait
,所有 Schema[T]
实例继承,ref[T]
查找 Schema[T]
的实例从隐式作用域和函数 integer
、long
和 float
构造一个给定示例的 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.
我正在使用来自 shapeless 的 Poly1
从实例构建案例 类(描述它们的序列化)的方案。构建
Schema
case class A(b: B, c: String, d: List[Int], e: Option[List[Option[Int]]])
每个包含的类型都需要一个架构。
一个 Schema
对象拥有(除其他外)其成员的示例值。我从所有 primitive 类型(Int
、Float
、String
、...)的实例中提取这些示例值,这些类型的方案构建于飞过我的 Poly1
。所有 complex 类型(我指的是具有其他成员值的自定义类型)都被引用,因为它们也可能具有自定义序列化方法。这很容易通过要求模式出现在隐式范围内来解决。
现在知道如何为任何列表(或任何其他集合)构造 Schema
iff 类型参数有一个 Schema
(s).这与其他 monad 类型相同,例如 Option
.
Poly1
的想法是将成员类型映射到它们的方案,这些方案要么即时构建,要么从隐式范围查找。这需要我为所有原始类型以及所有必要的单子定义一个案例。这种方法通常有效,但有很多样板。
当前 Poly1
对象(NGSchema
是一个 trait
,所有 Schema[T]
实例继承,ref[T]
查找 Schema[T]
的实例从隐式作用域和函数 integer
、long
和 float
构造一个给定示例的 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.