有谁知道在实际尝试在 REPL(或编译器)中编译之前如何获得(仅 Scala 部分)for/comprehension 表达式的脱糖翻译?
到目前为止,我发现的唯一东西是编译器“-print”标志,但它为您提供了完整的 Scala 翻译......
有谁知道在实际尝试在 REPL(或编译器)中编译之前如何获得(仅 Scala 部分)for/comprehension 表达式的脱糖翻译?
到目前为止,我发现的唯一东西是编译器“-print”标志,但它为您提供了完整的 Scala 翻译......
正如我在另一个主题中已经说过的那样,scalac -print
打印出 scala 代码,而不是 java。它将所有与 java 不直接兼容的 scala 关键字转换为普通的 scala 代码。不可能让编译器只翻译部分 afaik。但基本上,为了理解总是以同样的方式翻译。
像这样的简单 for/yield
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 中对“for/comprehension”表达式脱糖的任何可能性。但作为替代方案,可以使用一些 Scala 编译器选项,如“-print”或简单表达式“Xprint:typer -e”
例子:
要从文件中获取脱糖输出,请使用“-print”标志:
# scala -print file.scala
要对简单的单行表达式脱糖,请使用“-Xprint:typer -e”标志:
# scala -Xprint:typer -e "for (i <- 0 to 100) yield i"
宏呢?
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])
它也适用于其他任意表达式。
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
。
要查看简单脱糖后的结果,请使用该-Xprint:parser
选项。
如果您有这个名为的简单输入文件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。但是,您也会看到 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>
Intellij 有一个名为“解释 Scala ”的功能,它可以进行大量的脱糖,包括直接在您正在编辑的文件中将理解扩展到 map/flatMap/filter。
请注意,自 IntelliJ 2017.1 起,它现在称为“Desugar Scala 代码”,位于“代码”菜单中(感谢 Mikaël 提供的信息)。
在 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)