【问题标题】:Applying type constructors to generated type parameters with Scala macros使用 Scala 宏将类型构造函数应用于生成的类型参数
【发布时间】:2014-08-07 17:15:42
【问题描述】:

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

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写上apply的签名(如Foo[A]
  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

所以这似乎也不是解决方案。

【问题讨论】:

  • 你使用的是 scala 2.10 吗?
  • 另外,说到java.lang.IllegalArgumentException: can't splice "A" as type parameter,你能分享完整的代码吗?
  • 嘿尤金,我一直在使用 2.10,但据我所知,在 2.10 和 2.11.2 之间切换并没有任何区别。完整的(最终工作)代码现在lives here
  • 你试过appliedType吗?

标签: scala reflection macros type-constructor materialize


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-25
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    相关资源
    最近更新 更多