我正在尝试实现(简化)特征的实例
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
,原因有两个:
apply
(如F
)Foo[A]
的签名
Foo[A]
类型的成员,以便指定apply
有没有办法创建可以在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
所以这似乎也没有解决方案。
答案 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))
感觉完全没必要,但似乎这是摆脱冲突类型信息的唯一方法。