无形副产品子类型
Shapless coproduct sub-typing
我试图在 scala 2.13 中至少模拟联合类型的某些方面。
到目前为止,满足我需求的最佳方法是来自 shapless 的 coproduct
。唯一的问题是子类型没有像我预期的那样工作。这是一个例子:
import shapeless._
type ISB = Int :+: String :+: Boolean :+: CNil
type ISBSub = Int :+: String :+: CNil
implicitly[ISBSub <:< ISB] // error here
我正在尝试创建一个参数类型为 ISB
的方法,并希望此 def
也接受 ISBSub
。
def test(t: ISB) = ???
test(Coproduct[ISBSub](2)) // not working
有什么方法可以用 coproduct
实现这样的目标吗?
鉴于 Shapeless 对联积的编码,这种子集关系不可能与子类型相同。相反,有一种类型 class 提供了一个副产品是另一个副产品的子联合的证据:
scala> import shapeless._
import shapeless._
scala> type ISB = Int :+: String :+: Boolean :+: CNil
defined type alias ISB
scala> type ISBSub = Int :+: String :+: CNil
defined type alias ISBSub
scala> shapeless.ops.coproduct.Basis[ISB, ISBSub]
res0: shapeless.ops.coproduct.Basis[Int :+: String :+: Boolean :+: shapeless.CNil,Int :+: String :+: shapeless.CNil]{type Rest = Boolean :+: shapeless.CNil} = shapeless.ops.coproduct$Basis$$anon@ddd69d2
此类型 class 还允许您沿任一方向转换任一余积类型的值:
import shapeless.ops.coproduct.Basis
def shrink[A <: Coproduct, B <: Coproduct](a: A)(implicit ev: Basis[A, B]): Option[B] =
ev(a).toOption
def enlarge[A <: Coproduct, B <: Coproduct](b: B)(implicit ev: Basis[A, B]): A =
ev.inverse(Right(b))
然后:
scala> shrink[ISB, ISBSub](Coproduct[ISB](1))
res0: Option[ISBSub] = Some(Inl(1))
scala> enlarge[ISB, ISBSub](Coproduct[ISBSub](1))
res1: ISB = Inl(1)
一般来说,值得浏览 shapeless.ops
包的内容,以了解像联积这样的东西支持哪些类型的操作。
我试图在 scala 2.13 中至少模拟联合类型的某些方面。
到目前为止,满足我需求的最佳方法是来自 shapless 的 coproduct
。唯一的问题是子类型没有像我预期的那样工作。这是一个例子:
import shapeless._
type ISB = Int :+: String :+: Boolean :+: CNil
type ISBSub = Int :+: String :+: CNil
implicitly[ISBSub <:< ISB] // error here
我正在尝试创建一个参数类型为 ISB
的方法,并希望此 def
也接受 ISBSub
。
def test(t: ISB) = ???
test(Coproduct[ISBSub](2)) // not working
有什么方法可以用 coproduct
实现这样的目标吗?
鉴于 Shapeless 对联积的编码,这种子集关系不可能与子类型相同。相反,有一种类型 class 提供了一个副产品是另一个副产品的子联合的证据:
scala> import shapeless._
import shapeless._
scala> type ISB = Int :+: String :+: Boolean :+: CNil
defined type alias ISB
scala> type ISBSub = Int :+: String :+: CNil
defined type alias ISBSub
scala> shapeless.ops.coproduct.Basis[ISB, ISBSub]
res0: shapeless.ops.coproduct.Basis[Int :+: String :+: Boolean :+: shapeless.CNil,Int :+: String :+: shapeless.CNil]{type Rest = Boolean :+: shapeless.CNil} = shapeless.ops.coproduct$Basis$$anon@ddd69d2
此类型 class 还允许您沿任一方向转换任一余积类型的值:
import shapeless.ops.coproduct.Basis
def shrink[A <: Coproduct, B <: Coproduct](a: A)(implicit ev: Basis[A, B]): Option[B] =
ev(a).toOption
def enlarge[A <: Coproduct, B <: Coproduct](b: B)(implicit ev: Basis[A, B]): A =
ev.inverse(Right(b))
然后:
scala> shrink[ISB, ISBSub](Coproduct[ISB](1))
res0: Option[ISBSub] = Some(Inl(1))
scala> enlarge[ISB, ISBSub](Coproduct[ISBSub](1))
res1: ISB = Inl(1)
一般来说,值得浏览 shapeless.ops
包的内容,以了解像联积这样的东西支持哪些类型的操作。