【问题标题】:Avoiding recompilation with quasiquotes避免使用 quasiquotes 重新编译
【发布时间】:2014-01-27 18:48:28
【问题描述】:

在 Scala 中编写宏时,准引号可以简化很多事情。但是我注意到,每次触发 SBT 中的编译时,都可以重新编译包含 quasiquotes 的宏,即使宏实现和它的任何调用站点都没有更改并且需要重新编译。

这似乎不会发生,如果 quasiquotes 中的代码相当简单,它似乎只有在依赖于另一个类时才会发生。我注意到用“reify”重写所有内容似乎可以解决重新编译问题,但我无法在没有准引号的情况下重写最后一部分......

我的宏通过在编译期间创建包装函数来避免启动时反射。

我有以下课程:

object ExportedFunction {
  def apply[R: Manifest](f: Function0[R], fd: FunctionDescription): ExportedExcelFunction = new ExcelFunction0[R] {
    def apply: R = f()
    val functionDescription = fd
  }

  def apply[T1: Manifest, R: Manifest](f: Function1[T1, R], fd: FunctionDescription): ExportedExcelFunction = new ExcelFunction1[T1, R] {
    def apply(t1: T1): R = f(t1)
    val functionDescription = fd
  }

  ... and so on... until Function17...
}

然后我分析object 并使用所描述的接口导出任何成员函数,如下所示:

def export(registrar: FunctionRegistrar,
           root: Object,
           <...more args...>) = macro exportImpl

def exportImpl(c: Context)(registrar: c.Expr[FunctionRegistrar],
                           root: c.Expr[Object],
                           <...>): c.Expr[Any] = {             

  import c.universe._   

  <... the following is simplified ...>
  root.typeSignature.members.flatMap {
    case x if x.isMethod =>
      val method = x.asMethod     

      val callee = c.Expr(method))

      val desc = q"""FunctionDescription(<...result from reflective lookup...>)"""
      val export = q"ExportedFunction($callee _, $desc)"
      q"$registrar.+=({$export})"

我可以用 reify 重写第一行和最后一行,但我无法重写第二行,我最好的方法是使用 quasiquotes:

val export = reify {
  ...
     ExportedFunction(c.Expr(q"""$callee _"""), desc)
  ...
}.tree

但这会导致:

overloaded method value apply with alternatives... cannot be applied to (c.Expr[Nothing], c.universe.Expr[FunctionDescription])

我认为编译器缺少隐式,或者该代码可能仅适用于具有固定数量参数的函数,因为它需要在宏编译时知道该方法有多少参数?但是,如果所有内容都使用 quasiquotes 编写,则它可以工作...

【问题讨论】:

    标签: scala macros


    【解决方案1】:

    根据 SBT 问题的描述,我可以假设您正在使用 2.10.x 的宏天堂并且面临https://github.com/scalamacros/paradise/issues/11。我计划在本周解决这个问题,所以修复应该很快就会到来。同时,您可以使用问题页面上描述的解决方法。

    关于reify问题,并不是所有的quasiquotes都可以用reify重写。像您在这里遇到的限制是我们将注意力转移到 Scala 2.11 中的准引号的一个非常强大的动力。

    【讨论】:

    • 非常感谢最新版本!它解决了问题;-)
    • 但是,在项目中使用宏会使我们项目中的编译时间(即使没有要重新编译的文件)从 37 秒增加到 82 秒...
    • 您能否提供更多详细信息?看看一个需要 37 秒编译的 sbt 项目和另一个现在需要 82 秒编译的项目会很有帮助。
    【解决方案2】:

    为了记录,这些 SBT 设置(升级到较新版本)修复了它:

    ...
    settings = Seq(
      libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value,
      libraryDependencies += "org.scalamacros" % "quasiquotes" % "2.0.0-M3" cross CrossVersion.full,
      autoCompilerPlugins := true,
      addCompilerPlugin("org.scalamacros" % "paradise" % "2.0.0-M3" cross CrossVersion.full)
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-08
      • 1970-01-01
      • 2014-11-01
      • 2020-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多