我试图找到一种无形的方法来证明给定的产品类型没有延伸密封特性,因此不属于任何副产品。鉴于以下密封特征层次结构:
sealed trait Foo
case class Bar(a: Char) extends Foo
case class Baz(b: Int) extends Foo
我知道我可以使用shapeless.ops.coproduct.Basis
来证明某个选择或选择的后续序列属于联合产品。例如:
import shapeless._
type L = Bar :+: Baz :+: CNil
implicitly[ops.coproduct.Basis[L, Bar :+: CNil]]
我现在所做的是从选择中获取副产品的操作。例如。给定Bar
或Baz
,我希望返回L
,或者密封基本特征Foo
的类型。
这是无形的东西吗?或者,是否可以用宏来做?
更新
我最终编写了一个相当隐含的隐含宏......
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
trait SealedBaseTraitOf[A] {
type Repr
}
object SealedBaseTraitOf {
def materializeImpl[A](c: whitebox.Context)(implicit tag: c.WeakTypeTag[A]): c.Expr[SealedBaseTraitOf[A]] = {
import c.universe._
val a = weakTypeOf[A].typeSymbol
val baseClasses = a.asClass.baseClasses
val maybeBaseTrait =
baseClasses
.find(t => t.asClass.isTrait && t.asClass.isSealed)
.map(_.asType.name)
val repr = maybeBaseTrait.map(t => tq"$t").getOrElse(tq"Nothing")
println(s"Got a repr: $repr")
c.Expr[SealedBaseTraitOf[A]](q"""
new SealedBaseTraitOf[$a] {
type Repr = $repr
}
""")
}
implicit def materialize[A]:SealedBaseTraitOf[A] = macro materializeImpl[A]
}
将所有内容放在一起,可以按如下方式使用宏:
case class ExtendsNothing(a: Int)
sealed trait X
case class ExtendsX(b: Char) extends X
import shapeless._
val bt1 = the[SealedBaseTraitOf[ExtendsNothing]]
implicitly[bt1.Repr =:= Nothing]
val bt2 = the[SealedBaseTraitOf[ExtendsX]]
implicitly[bt2.Repr =:= X]
val coprodX = Generic[X]
val coprodBt2 = Generic[bt2.Repr]
implicitly[coprodX.Repr =:= coprodBt2.Repr]
implicitly[ops.coproduct.Basis[coprodBt2.Repr, ExtendsX :+: CNil]]
在接近解决方案时,我仍然希望找到一些不那么复杂的东西,可能不涉及使用宏。