Я изучаю scala, и для выполнения задания мне нужно написать макрос.
Макрос должен исследовать дерево выражений и затем создать пользовательский Expression
.Мне удалось «взглянуть» на выражение, добавив println(showRaw(exprTree))
.Однако я все еще не смог перебрать его и построить Expression
У меня есть следующие два файла:
ExpressionImplicits.scala :
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
// Expression is defined elsewhere and mainly only overrides toString()
abstract class Expression
case class Var(name: String) extends Expression
case class Number(num: Double) extends Expression
case class BinOp(operator: String, left: Expression, right: Expression) extends Expression
class ExpressionImplicitsImpl(val c: Context) {
import c.universe._
// Task complete macro
// Add necessary definitions here
// This definition was added by me
def expr(exprTree: c.Expr[AnyRef]): c.Expr[Expression] = {
println(showRaw(exprTree))
//prints
//Expr(Function(List(ValDef(Modifiers(PARAM), TermName("x"), TypeTree().setOriginal(Select(Ident(scala), scala.Double)), EmptyTree)), Apply(Select(Apply(Select(Ident(TermName("x")), TermName("$times")), List(Literal(Constant(2)))), TermName("$plus")), List(Apply(Select(Literal(Constant(3.0)), TermName("$times")), List(Ident(TermName("x"))))))))
//Expr(Function(List(ValDef(Modifiers(PARAM), TermName("x"), TypeTree().setOriginal(Select(Ident(scala), scala.Double)), EmptyTree), ValDef(Modifiers(PARAM), TermName("y"), TypeTree().setOriginal(Select(Ident(scala), scala.Double)), EmptyTree)), Apply(Select(Apply(Select(Ident(TermName("x")), TermName("$times")), List(Ident(TermName("y")))), TermName("$times")), List(Ident(TermName("x"))))))
}
}
// This definition is given
object ExpressionImplicits {
def expr(exprTree: AnyRef): Expression = macro ExpressionImplicitsImpl.expr
}
ExpressionsTest.scala :
object ExpressionsTest {
def main(args: Array[String]) {
import ExpressionImplicits._
val e1 = expr { (x: Double) => (x * 2) + (3.0 * x) }
println(e1) // BinOp(+,BinOp(*,Var(x),Number(2.0)),BinOp(*,Number(3.0),Var(x)))
val e2 = expr { (x: Double, y: Double) => x * y * x }
println(e2) // BinOp(*,BinOp(*,Var(x),Var(y)),Var(x))
// val e3 = expr { (x: Double) => x.toInt } // Fails during compilation
}
}