gpt4 book ai didi

scala - 在 Scala 中使用 reify(获取 AST)表达式的最简单方法是什么?

转载 作者:行者123 更新时间:2023-12-02 05:01:04 27 4
gpt4 key购买 nike

我正在寻找 -printjavap 的替代方案来了解编译器在 Scala 中执行的操作。有了新的反射/宏库,reify 似乎是一个很好的候选者,如 Retronym 的 macrocosm 所示。的脱糖。它甚至展示了在 M4 之前人们是如何做到这一点的。

所以问题是,在 Scala 2.10.0-M4 之后,我可以在 Scala 的 REPL 上输入来获取表达式的 AST 的最短/最简单的内容是什么?

最佳答案

之前在 scala.reflect.mirror 包中定义的许多内容已移至 scala.reflect.runtime.universe:

scala> import scala.reflect.runtime.{universe => u}
import scala.reflect.runtime.{universe=>u}

scala> val expr = u reify { 1 to 3 map (_+1) }
expr: reflect.runtime.universe.Expr[scala.collection.immutable.IndexedSeq[Int]] = Expr[scala.collection.immutable.IndexedSeq[Int]](scala.this.Predef.intWrapper(1).to(3).map(((x$1) => x$1.$plus(1)))(immutable.this.IndexedSeq.canBuildFrom))

scala> u show expr.tree
res57: String = scala.this.Predef.intWrapper(1).to(3).map(((x$1) => x$1.$plus(1)))(immutable.this.IndexedSeq.canBuildFrom)

scala> u showRaw expr.tree
res58: String = Apply(Apply(Select(Apply(Select(Apply(Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("intWrapper")), List(Literal(Constant(1)))), newTermName("to")), List(Literal(Constant(3)))), newTermName("map")), List(Function(List(ValDef(Modifiers(<param> <synthetic>), newTermName("x$1"), TypeTree(), EmptyTree)), Apply(Select(Ident(newTermName("x$1")), newTermName("$plus")), List(Literal(Constant(1))))))), List(Select(Select(This(newTypeName("immutable")), newTermName("IndexedSeq")), newTermName("canBuildFrom"))))

此外,还可以检查包含某些 Scala 代码的字符串是否是有效的 Scala 表达式,甚至更好 - 进行一些评估:

编辑。在 2.10.0-RC1 中,ToolBox 的一些方法已被重命名。 parseExpr 现在只是 parserunExpr 现在称为 eval

scala> import scala.tools.reflect.ToolBox
import scala.tools.reflect.ToolBox

scala> import scala.reflect.runtime.{currentMirror => m}
import scala.reflect.runtime.{currentMirror=>m}

scala> val tb = m.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@9293709

scala> val tree = tb.parse("1 to 3 map (_+1)")
tree: tb.u.Tree = 1.to(3).map(((x$1) => x$1.$plus(1)))

scala> val eval = tb.eval(tree)
eval: Any = Vector(2, 3, 4)

这里最复杂的事情是表达式的原始树表示。当想要使用宏时,必须按照 showRaw 所示的相同方式定义宏。但是使用一些辅助方法可以定义一些看起来不太难看的宏实现:

object IntMacro {

import language.experimental.macros
import scala.reflect.makro.Context
import scala.reflect.NameTransformer.encode

def isEven(i: Int): Boolean = macro isEvenImpl

def isEvenImpl(c: Context)(i: c.Expr[Int]): c.Expr[Boolean] = {
import c.universe._
implicit val cc: c.type = c

val `x = i%2` = Apply(Select(i.tree, op("%")), const(2))
val `x == 0` = Apply(Select(`x = i%2`, op("==")), const(0))

c.Expr(`x == 0`)
}

def op(s: String)(implicit c: Context): c.universe.TermName =
c.universe.newTermName(encode(s))

def const(a: Any)(implicit c: Context): List[c.universe.Literal] =
List(c.universe.Literal(c.universe.Constant(a)))
}

scala> import IntMacro._
import IntMacro._

scala> isEven(2)
res60: Boolean = true

scala> isEven(3)
res61: Boolean = false

但是现在我们遇到了路径相关类型的问题 - 如果我们不想导入它们,我们必须显式地编写它们的路径。

关于scala - 在 Scala 中使用 reify(获取 AST)表达式的最简单方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11055210/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com