获得Scala的desugared部分/理解expression?
有没有人知道如何得到(Scala部分只)desugared for / comprehensionexpression式之前它实际上试图在REPL(或编译器)编译?
我迄今为止唯一发现的是编译器“-print”标志,但是它给了你全面的Scala翻译…
正如我已经在其他主题中所说的, scalac -print
打印scala代码,而不是java。 它将所有不与java直接兼容的scala关键字翻译成普通的scala代码。 编译器不能只翻译部分afaik。 但基本上,理解总是以同样的方式翻译。
一个简单的/像这样的产量
for(x <- List(1,2,3)) yield x*x
将被翻译成
List(1,2,3).map {x => x*x}
没有收益
for(x <- List(1,2,3)) println(x)
至
List(1,2,3).foreach{x => println(x)}
嵌套的fors将被转换为嵌套的flatMap / map结构
for(x <- List(1,2,3); y <- List(4,5,6)) yield x*y
将被翻译成
List(1,2,3).flatMap { x => List(4,5,6).map { y => x*y } }
所以绝对没有魔法
似乎没有任何可能性直接在REPL中parsing“for / comprehension”expression式。 但作为替代,可以使用一些Scala编译器选项,如“-print”或简单expression式“Xprint:typer -e”
例:
要从文件中获得desugard输出,请使用“-print”标志:
# scala -print file.scala
要解开简单的单行expression式,请使用“-Xprint:typer -e”标志:
# scala -Xprint:typer -e "for (i <- 0 to 100) yield i"
macros如何?
import scala.reflect.macros.Context import scala.reflect.runtime.universe._ import scala.language.experimental.macros def _desugar(c : Context)(expr : c.Expr[Any]): c.Expr[Unit] = { import c.universe._ println(show(expr.tree)) reify {} } def desugar(expr : Any) = macro _desugar
根据您的要求,这可以直接在REPL中使用:
scala> desugar { for(i <- List(1,2,3,4,5)) yield i } immutable.this.List.apply[Int](1, 2, 3, 4, 5).map[Int, Any](((i: Int) => i))(immutable.this.List.canBuildFrom[Int]) scala> desguar { for(i <- (0 to 10) if (i > 5)) yield i } scala.this.Predef.intWrapper(0).to(10).withFilter(((i: Int) => i.>(5))).map[Int, Any](((i: Int) => i))(immutable.this.IndexedSeq.canBuildFrom[Int])
它也适用于其他任意expression式。
scala> desugar { | val x = 20 | val y = 10 | println(x + y) | } { val x: Int = 20; val y: Int = 10; scala.this.Predef.println(x.+(y)) }
这可能是最接近你所要求的,而无需在任何时候将数据编译或转储到文件。 您可以直接在REPL中或在用:load
命令加载的外部文件中定义macros。
为了在简单的parsing之后看到结果,使用-Xprint:parser
选项。
如果你有这个简单的input文件test.scala
:
object Test { for(x <- List(1,2,3); y <- List(4,5,6)) yield x*y }
然后使用scalac -Xprint:parser
编译它打印出来:
$ scalac -Xprint:parser test.scala [[syntax trees at end of parser]] // test.scala package <empty> { object Test extends scala.AnyRef { def <init>() = { super.<init>(); () }; List(1, 2, 3).flatMap(((x) => List(4, 5, 6).map(((y) => x.$times(y))))) } }
要获得适用于-Xprint:<phase>
的编译器阶段的完整列表,请执行以下操作:
$ scalac -Xshow-phases phase name id description ---------- -- ----------- parser 1 parse source into ASTs, perform simple desugaring namer 2 resolve names, attach symbols to named trees packageobjects 3 load package objects typer 4 the meat and potatoes: type the trees patmat 5 translate match expressions superaccessors 6 add super accessors in traits and nested classes extmethods 7 add extension methods for inline classes pickler 8 serialize symbol tables refchecks 9 reference/override checking, translate nested objects selectiveanf 10 selectivecps 11 uncurry 12 uncurry, translate function values to anonymous classes tailcalls 13 replace tail calls by jumps specialize 14 @specialized-driven class and method specialization explicitouter 15 this refs to outer pointers, translate patterns erasure 16 erase types, add interfaces for traits posterasure 17 clean up erased inline classes lazyvals 18 allocate bitmaps, translate lazy vals into lazified defs lambdalift 19 move nested functions to top level constructors 20 move field definitions into constructors flatten 21 eliminate inner classes mixin 22 mixin composition cleanup 23 platform-specific cleanups, generate reflective calls icode 24 generate portable intermediate code inliner 25 optimization: do inlining inlineExceptionHandlers 26 optimization: inline exception handlers closelim 27 optimization: eliminate uncalled closures dce 28 optimization: eliminate dead code jvm 29 generate JVM bytecode terminal 30 The last phase in the compiler chain
-Xprint:<phase>
选项也适用于scala
,因此适用于REPL。 但是,您将看到REPL插入的所有包装器代码。
$ scala -Xprint:parser Welcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_25). Type in expressions to have them evaluated. Type :help for more information. <..a lot of initialisation code printed..> scala> object Test { | for(x <- List(1,2,3); y <- List(4,5,6)) yield x*y | } [[syntax trees at end of parser]] // <console> package $line3 { object $read extends scala.AnyRef { def <init>() = { super.<init>(); () }; object $iw extends scala.AnyRef { def <init>() = { super.<init>(); () }; object $iw extends scala.AnyRef { def <init>() = { super.<init>(); () }; object Test extends scala.AnyRef { def <init>() = { super.<init>(); () }; List(1, 2, 3).flatMap(((x) => List(4, 5, 6).map(((y) => x.$times(y))))) } } } } } [[syntax trees at end of parser]] // <console> package $line3 { object $eval extends scala.AnyRef { def <init>() = { super.<init>(); () }; lazy val $result = $line3.$read.$iw.$iw.Test; val $print: String = { $read.$iw.$iw; "".$plus("defined module ").$plus("Test").$plus("\n") } } } defined module Test scala>
在scala 2.11中,也可以使用quasiquotes :
val universe: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe import universe._ val tree = q""" val x = 20 val y = 10 println(x + y) """ println(tree)
Intellij有一个名为“ Explain Scala ”的function,它可以在你正在编辑的文件中直接进行map / flatMap / filter的扩展。
请注意,自从IntelliJ 2017.1这个现在被称为“Desugar Scala代码”,并在“代码”菜单(感谢Mikaël的信息)。