获得Scala的desugared部分/理解表达式?

IOD*_*DEV 25 scala syntactic-sugar for-comprehension

有没有人知道在实际尝试在REPL(或编译器)中编译之前如何获取(仅Scala部分)desgoared for for/comprehension表达式?

到目前为止,我唯一发现的是编译器"-print"标志,但它为您提供了完整的Scala转换...

dre*_*xin 35

正如我在其他主题中已经说过的那样,scalac -print打印出scala代码,而不是java.它将所有与java不直接兼容的scala关键字转换为普通的scala代码.不可能让编译器只翻译afaik部分.但基本上,理解总是以同样的方式翻译.

像这样的简单/收益

for(x <- List(1,2,3)) yield x*x
Run Code Online (Sandbox Code Playgroud)

将被翻译成

List(1,2,3).map {x => x*x}
Run Code Online (Sandbox Code Playgroud)

没有收益

for(x <- List(1,2,3)) println(x)
Run Code Online (Sandbox Code Playgroud)

List(1,2,3).foreach{x => println(x)}
Run Code Online (Sandbox Code Playgroud)

嵌套的fors将被转换为嵌套的flatMap/map构造

for(x <- List(1,2,3); y <- List(4,5,6)) yield x*y
Run Code Online (Sandbox Code Playgroud)

将被翻译成

List(1,2,3).flatMap { x =>
  List(4,5,6).map { y =>
    x*y
  }
}
Run Code Online (Sandbox Code Playgroud)

所以绝对没有魔力

  • 我的坏,你是对的!我还发现了简单表达式的编译器-e标志,如:scala -Xprint:typer -e"val i = 1" (7认同)

IOD*_*DEV 24

似乎没有任何可能直接在REPL中去除"for/comprehension"表达式.但作为替代方案,可以使用一些Scala编译器选项,如"-print"或简单表达式"Xprint:typer -e"

例:

要从文件中获取desugard输出,请使用"-print"标志:

# scala -print file.scala
Run Code Online (Sandbox Code Playgroud)

要使用简单的单行表达式,请使用"-Xprint:typer -e"标志:

# scala -Xprint:typer -e "for (i <- 0 to 100) yield i"
Run Code Online (Sandbox Code Playgroud)

  • 首先,您应该使用`-Xprint:parser`来仅查看desugaring.此外,您可以将此与REPL一起使用,例如`scala -Xprint:parser`.但是,它还会显示REPL为您的代码提供的所有包装代码. (4认同)

KCh*_*oux 23

一个宏怎么样?

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
Run Code Online (Sandbox Code Playgroud)

根据您的要求,这可以直接在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])
Run Code Online (Sandbox Code Playgroud)

它也适用于其他任意表达式.

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))
}
Run Code Online (Sandbox Code Playgroud)

这可能是您最接近您所要求的,而无需在任何时候将数据编译或转储到文件中.您可以直接在REPL中或在使用该:load命令加载的外部文件中定义宏.


mgd*_*mgd 17

要在简单的desugaring之后查看结果,请使用该-Xprint:parser选项.

如果您有这个简单的输入文件名为test.scala:

object Test {
  for(x <- List(1,2,3); y <- List(4,5,6)) yield x*y
}
Run Code Online (Sandbox Code Playgroud)

然后使用scalac -Xprint:parserprint out 编译它:

$ 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)))))
  }
}
Run Code Online (Sandbox Code Playgroud)

要获得适用-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
Run Code Online (Sandbox Code Playgroud)

-Xprint:<phase>选项也适用于scalaREPL,因此也适用于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> 
Run Code Online (Sandbox Code Playgroud)


Cho*_*ack 9

Intellij有一个名为" Explain Scala "的功能,可以完成大量的工作,包括直接在你正在编辑的文件中将理解扩展到map/flatMap/filter中.

请注意,因为IntelliJ 2017.1现在称为"Desugar Scala代码",并且位于"代码"菜单中(感谢Mikaël提供的信息).

IntelliJ Desugar Scala