递归评估Scala抽象语法树

3
假设我有一个lambda函数,并使用reify将其转换为包装在Tree中的Expr。例如:
val expr = reify{x: Int => 3*(4+x)}

我可以按照以下方式为特定的x进行评估:
val toolbox = currentMirror.mkToolBox()
val fun = toolbox.eval(expr.tree).asInstanceOf[Int => Int]
println(fun(10))

我的目标是打印整个树,带有每个子表达式的值的注释。如何确定所有子表达式及其值?例如,确定当x为10时,存在一个子表达式

(4+x)

这段代码应该返回14。Traverser类让我能够访问树中的每个节点,但我无法弄清如何在每个节点处计算子树。

例如,对于以下代码:

class TestTraverser extends Traverser {
  override def traverse(tree: Tree): Unit = {
    val toolbox = currentMirror.mkToolBox()
    tree match {
      case app @ Apply(fun, args) =>
        val f = toolbox.eval(app.fun)
      case _ =>
    }
    super.traverse(tree)
  }
}

呼叫
new TestTraverser().traverse(expr.tree)

导致此异常的原因。
scala.tools.reflect.ToolBoxError: reflective compilation has failed:

ambiguous reference to overloaded definition,
both method * in class Int of type (x: Char)Int
and  method * in class Int of type (x: Byte)Int
match expected type Any

调用 eval 用于子树? - Ashalynd
你可能会认为有一些方法可以在子树上调用eval,但我没有找到这样的方法。我已经添加了一个尝试这样做但不起作用的遍历器。 - Michael Altmann
1个回答

2

我自己解决了这个问题。为了在子树上调用toolbox.eval,您需要重新包装子树,并提供指示它是一个名为xInt函数的信息。下面是一个有效的Traverser示例。

class WorkingTraverser extends Traverser {
  val toolbox = currentMirror.mkToolBox()
  override def traverse(tree: Tree): Unit = {
    tree match {
      case app @ Apply(fun, args) =>
        val newfun = Function(List(ValDef(Modifiers(PARAM), TermName("x"), Ident(TypeName("Int")), EmptyTree)), Apply(app.fun, app.args))
        val f = toolbox.eval(newfun)
        val f2 = f.asInstanceOf[Int => Int]
        println(app.fun + "(" + app.args + ")" + " evaluates to " + f2(10))
        super.traverse(fun)
        super.traverseTrees(args)
      case _ => super.traverse(tree)
    }
  }
}

完全离题,但是,你知道“@”语法叫什么吗?我不明白如何阅读它,它的意义是什么,还有哪些地方可以使用它等等。 - Lucas Lima

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接