无礼的副产品子类型

时间:2019-09-21 14:38:10

标签: scala shapeless

我试图至少在Scala 2.13中模拟联合类型的某些方面。

到目前为止,满足我需求的最佳方法是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来达到这样的目的?

1 个答案:

答案 0 :(得分:8)

鉴于Shapeless对副产品的编码,这种子集关系不可能与子类型相同。而是有一个类型类提供证据,证明一个副产品是另一个副产品的子联盟:

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$64@ddd69d2

此类型类还允许您在任一方向上转换任一副产品类型的值:

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软件包的内容,以了解对诸如副产品之类的东西支持哪些操作。