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



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

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. 为特定的F(如Foo[A])编写上述apply的签名
  2. 检查Foo[A]类型的成员,以指定apply的有趣主体

是否有任何方法可以创建与方法类型参数A相对应的类型,而可以在appliedType中使用?这对我来说似乎很困难,因为方法apply和它的类型参数A也只是作为树生成的。


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

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

但是在q"... def apply[$paramT] ..."中使用paramT确实会产生

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

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

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

来解决这个问题
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

类型检查的结果可以被解构和转换(通过树转换器)来填充???。这并没有完全解决问题,产生了类型错误:

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

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

相关内容

  • 没有找到相关文章

最新更新