32

REPL (またはコンパイラ) で実際にコンパイルしようとする前に、for/comprehension 式の (Scala 部分のみ) desugar 変換を取得する方法を知っている人はいますか?

私がこれまでに見つけた唯一のものは、コンパイラの「-print」フラグですが、これで Scala の完全な翻訳が得られます…

4

6 に答える 6

36

他のトピックで既に述べたように、scalac -printjava ではなく scala コードを出力します。Java と直接互換性がないすべての scala キーワードを通常の scala コードに変換します。コンパイラーに一部のみを翻訳させることはできません。しかし、基本的には for-comprehension は常に同じように翻訳されます。

このような単純な 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)}

ネストされた for は、ネストされた 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
  }
}

だから魔法は絶対にない

于 2012-03-27T14:35:12.350 に答える
26

REPL内で直接「for/comprehension」式を脱糖する可能性はないようです。しかし、別の方法として、「-print」や単純な式「Xprint:typer -e」などの Scala コンパイラ オプションを使用できます。

例:

ファイルから desugard 出力を取得するには、「-print」フラグを使用します。

# scala -print file.scala

単純なワンライナー式を desugar するには、「-Xprint:typer -e」フラグを使用します。

# scala -Xprint:typer -e "for (i <- 0 to 100) yield i"
于 2012-03-27T15:12:05.787 に答える
25

マクロはどうですか?

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コマンドでロードされた外部ファイルで定義できます。

于 2013-11-04T18:21:30.553 に答える
17

単純な脱糖後の結果を確認するには、-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>オプションは REPL にも適用できる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> 
于 2013-10-30T07:42:48.500 に答える
4

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)
于 2015-08-20T13:43:20.787 に答える