使用Scala宏将类型构造函数应用于生成的类型参数

时间:2014-08-07 17:15:43

标签: scala reflection macros type-constructor materialize

我正在尝试实现(简化)特征的实例

trait TC[F[_]] {
  def apply[A](fa: F[A]): F[A]
}

使用Scala宏。因此宏的签名是

def materialize[F[_]](c: Context)(
  implicit fT: c.WeakTypeTag[F[_]]): c.Expr[TC[F]]

现在需要将类型构造函数F[_]应用于类型参数A,原因有两个:

  1. 为特定apply(如F
  2. 撰写上述Foo[A]的签名
  3. 要检查Foo[A]类型的成员,以便指定apply
  4. 的有趣主体

    有没有办法创建可以在A中使用的方法类型参数appliedType对应的类型?这对我来说似乎很难,因为方法apply及其类型参数A也只是作为树生成。


    我尝试将WeakTypeTag[TC[F]]作为宏调用的附加参数,并通过

    接收参数类型
    val paramT = wfg.tpe.member("apply": TermName).tpe.typeParams.head.tpe
    

    然后在paramT中使用q"... def apply[$paramT] ..."会导致

    java.lang.IllegalArgumentException: can't splice "A" as type parameter
    

    所以这似乎也没有解决方案。

1 个答案:

答案 0 :(得分:0)

我通过将上述特征的定义更改为

来解决了这个问题
trait TC[F[_]] {
  type ApplyF[A] = F[A]
  def apply[A](fa: ApplyF[A]): ApplyF[A]
}

对树进行类型检查以获取虚拟值

typecheck(q"""new TC[Foo] {
  def apply[A](fa: ApplyF[A]): ApplyF[A] = ???
}""").tpe

然后可以破坏和转换类型检查结果(通过tree transformers)以填充???。这并没有完全解决问题,产生类型错误:

found   : A(in method apply)(in method apply)(in method apply)...
required: A(in method apply)(in method apply)(in method apply)...

在返回树之前调用untypecheck没有帮助 - 检查结果树然后显示预期结果是有效的(类型正确)Scala代码。因此,使宏最终飞行的最后一步是调用

parse(showCode(result))

感觉完全没必要,但似乎这是摆脱冲突类型信息的唯一方法。