我正在尝试实现(简化)特征的实例
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
,原因有两个:
- 为特定的
F
(如Foo[A]
)编写上述apply
的签名 - 检查
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))
感觉完全没有必要,但这似乎是摆脱冲突类型信息的唯一方法。