scala 在定义宏的同一文件中使用宏有什么诀窍吗?

taor4pac  于 2022-11-09  发布在  Scala
关注(0)|答案(2)|浏览(141)

我有以下代码:

object Macros {

  import scala.language.experimental.macros
  import scala.reflect.macros.blackbox

  def hello(): Unit = macro hello_impl

  def hello_impl(c: blackbox.Context)(): c.Expr[Unit] = {
    import c.universe._
    reify {
      println("Hello World!")
    }
  }
}

object Main {

  def main(args: Array[String]): Unit = {
    Macros.hello()
  }

}

它引发以下编译错误:

Error:(21, 17) macro implementation not found: hello
(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
    Macros.hello()
                ^

我的问题是:有没有办法“愚弄”编译器,以便在定义它们的同一文件中使用宏扩展?我的动机如下:我喜欢用Scala编写代码,最近我在在线评测Codeforces中提交了一些问题,结果发现一些Scala构造非常慢。所以,我想要创建一些宏扩展,以便快速执行这些构造。但我不能提交多份文件。
谢谢!

mrfwxfqh

mrfwxfqh1#

目前,这在Scala 2.10和2.11的生产版本中是不可能的。我们或许能够使用scala.meta实现这一点,但那是很好的未来。

9nvpjoqh

9nvpjoqh2#

这取决于“使用”的含义。原则上,如果第二个方法也是宏(第一个方法调用必须在准引号q"..."内,而不是reify{...}内),则可以在同一文件中的另一个方法(foo)中使用宏(hello)

import scala.language.experimental.macros
import scala.reflect.macros.blackbox // libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value

object Macros {
  def hello(): Unit = macro hello_impl

  def hello_impl(c: blackbox.Context)(): c.Expr[Unit] = {
    import c.universe._
    reify {
      println("Hello World!")
    }
  }
}

object Main {
  def foo(): Unit = macro fooImpl

  def fooImpl(c: blackbox.Context)(): c.Tree = {
    import c.universe._
    q"Macros.hello()"
  }
}

https://scastie.scala-lang.org/DmytroMitin/rom8yKvmSUGVk0GwtGzKqQ
问题是,可运行的def main(args: Array[String]): Unit不能是宏。
另一种选择是反射工具箱。宏不能用工具箱定义(需要实际的编译器)

import scala.reflect.runtime
import scala.reflect.runtime.universe.Quasiquote
import scala.tools.reflect.ToolBox // libraryDependencies += scalaOrganization.value % "scala-compiler" % scalaVersion.value

val rm = runtime.currentMirror
val tb = rm.mkToolBox()
tb.compile(q"""
  import scala.language.experimental.macros
  import scala.reflect.macros.blackbox.Context
  def bar(): Unit = macro barImpl
  def barImpl(c: Context)(): c.Tree = {
    import c.universe._
    EmptyTree
  }
""")
//macro implementation reference has wrong shape. required:
//macro [<static object>].<method name>[[<type args>]] or
//macro [<macro bundle>].<method name>[[<type args>]]

但宏可以使用工具箱运行

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

object Macros {
  def hello(): Unit = macro hello_impl

  def hello_impl(c: blackbox.Context)(): c.Expr[Unit] = {
    import c.universe._
    reify {
      println("Hello World!")
    }
  }
}

import scala.reflect.runtime
import scala.reflect.runtime.universe.Quasiquote
import scala.tools.reflect.ToolBox

object Main {
  def main(args: Array[String]): Unit = {
    val rm = runtime.currentMirror
    val tb = rm.mkToolBox()
    tb.eval(q"Macros.hello()")
  }
}
// Hello World!

https://scastie.scala-lang.org/DmytroMitin/rom8yKvmSUGVk0GwtGzKqQ/5
关于CodeForCES,问题是编译器必须在类路径中,通过工具箱调用相对较慢。
Possible to identify/use Scala macros using reflection or similar?(Scala 3)

相关问题