Viele Dinge vorher im Paket definiert scala.reflect.mirror
zu scala.reflect.runtime.universe
bewegt hat:
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"))))
Das Weiteren ist es möglich, wenn ein String-Code enthält einige Scala zu prüfen, ein gültiger Scala Ausdruck ist und - noch besser - einige tun Bewertung:
Bearbeiten. In 2.10.0-RC1 wurden einige Methoden von ToolBox
umbenannt. parseExpr
ist jetzt nur parse
, und runExpr
heißt jetzt 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] = [email protected]
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)
Die komplizierteste Sache hier ist die rohe Baumdarstellung eines Ausdrucks. Wenn Makros verwendet werden sollen, müssen die Makros genau so definiert werden, wie es in showRaw
angezeigt wird. Aber mit einigen Helfermethoden ist es möglich, einige nicht so hässlich makro-Implementierungen zu definieren:
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
Aber jetzt kommen wir in Probleme mit wegabhängigen-Typen - müssen wir ihre Wege explizit schreiben, wenn wir nicht importieren wollen Sie.
Einfacher als 'reflect.runtime.universe.reify (für (i <- 1 bis 10) Ausbeute i * 2) .tree'? –
@TravisBrown Hört sich gut an, aber ich kann nur Antworten akzeptieren, keine Kommentare. :-) –