Получаете desugared часть Scala для выражения / понимания? - PullRequest
25 голосов
/ 27 марта 2012

Кто-нибудь знает, как получить (отчасти Scala) отлаженный перевод выражения для / понимания прежде, чем оно действительно попытается скомпилировать в REPL (или компиляторе)?

Единственное, что я нашел до сих пор, это флаг компилятора "-print", но он дает вам полный перевод Scala ...

Ответы [ 6 ]

35 голосов
/ 27 марта 2012

Как я уже говорил в другой теме, scalac -print печатает код scala, а не java.Он переводит все ключевые слова scala, которые напрямую не совместимы с Java, в обычный код scala.Невозможно позволить компилятору переводить только части afaik.Но в основном для понимания всегда переводится одинаково.

Простой for / yield, подобный этому

for(x <- List(1,2,3)) yield x*x

будет переведен в

List(1,2,3).map {x => x*x}

И безyield

for(x <- List(1,2,3)) println(x)

до

List(1,2,3).foreach{x => println(x)}

Вложенные форы будут переведены во вложенные конструкции 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
  }
}

Так что магии абсолютно нет

24 голосов
/ 27 марта 2012

Кажется, что нет никаких возможностей десугаровать выражения "для / понимания" непосредственно в REPL.Но в качестве альтернативы можно использовать некоторые параметры компилятора Scala, такие как «-print» или для простых выражений «Xprint: typer -e»

Пример:

Чтобы получить вывод десугарда из файла, используйтефлаг "-print":

# scala -print file.scala

Чтобы десагарировать простое однострочное выражение, используйте флаг "-Xprint: typer -e":

# scala -Xprint:typer -e "for (i <- 0 to 100) yield i"
23 голосов
/ 04 ноября 2013

Как насчет макроса?

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.

17 голосов
/ 30 октября 2013

Чтобы увидеть результат после простого удаления ошибок, используйте параметр -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.

$ 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> 
9 голосов
/ 19 декабря 2016

Intellij имеет функцию под названием " Explain Scala ", которая выполняет ОЧЕНЬ много десагеринга, включая расширение для понимания в map / flatMap / filter непосредственно в файле, который вы редактируете.

Обратите внимание, что начиная с IntelliJ 2017.1 он теперь называется «Код Desugar Scala» и находится в меню «Код» (спасибо Микаэль за информацию).

IntelliJ Desugar Scala

3 голосов
/ 20 августа 2015

В Scala 2.11 также можно использовать квазицитаты :

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)
...