从选择

时间:2017-11-10 16:30:18

标签: scala shapeless scala-macros type-level-computation

我试图找到一种无形的方法来证明给定的产品类型没有延伸密封特性,因此不属于任何副产品。鉴于以下密封特征层次结构:

  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]]

我现在所做的是从选择中获取副产品的操作。例如。给定BarBaz,我希望返回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]]

在接近解决方案时,我仍然希望找到一些不那么复杂的东西,可能不涉及使用宏。

0 个答案:

没有答案