2

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

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

有什么方法可以创建与方法类型参数对应的类型A,而不是使用appliedType?这对我来说似乎很困难,因为该方法apply及其类型参数A也只是作为树生成的。


我试图将WeakTypeTag[TC[F]]宏调用的附加参数作为附加参数,并通过以下方式接收参数类型

val paramT = wfg.tpe.member("apply": TermName).tpe.typeParams.head.tpe

但随后使用paramTinq"... def apply[$paramT] ..."确实会导致

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

所以这似乎也没有解决办法。

4

1 回答 1

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

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

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

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

于 2014-08-08T00:17:40.727 回答