scala syntactic-sugar for-comprehension

¿Conseguir la parte desugared de un Scala para la expresión de comprensión?



syntactic-sugar for-comprehension (6)

¿Qué tal una macro?

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

Esto se puede utilizar directamente en el REPL, según su solicitud:

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

También funciona en otras expresiones arbitrarias.

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

Es probable que esto sea lo más cercano a lo que está pidiendo sin tener que compilar o volcar los datos en un archivo en ningún momento. Puede definir la macro directamente en el REPL, o en un archivo externo cargado con el comando :load .

¿Alguien sabe cómo obtener la traducción desugared (solo parte de Scala) de una expresión para / comprensión antes de que realmente intente compilar en el REPL (o compilador)?

Lo único que he encontrado hasta ahora es el indicador "-print" del compilador, pero eso te da la traducción completa de Scala ...


En scala 2.11, también es posible usar 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 tiene una función llamada " Explicar Scala " que hace MUCHO desugaring, incluida la expansión para comprensión en map / flatMap / filter directamente en el archivo que está editando.

Tenga en cuenta que desde IntelliJ 2017.1, ahora se llama "Código de Desugar Scala" y se encuentra en el menú "Código" (gracias a Mikaël por la información).


No parece existir ninguna posibilidad de desugar expresiones "para / comprensión" directamente dentro del REPL. Pero como alternativa, se pueden usar algunas opciones del compilador Scala como "-print" o para expresiones simples "Xprint: typer -e"

Ejemplo:

Para obtener la salida de desugard de un archivo, use la marca "-print":

# scala -print file.scala

Para desugar una simple expresión de una línea, use el indicador "-Xprint: typer -e":

# scala -Xprint:typer -e "for (i <- 0 to 100) yield i"


Para ver el resultado después de una eliminación de fugas simple, use la opción -Xprint:parser .

Si tiene este simple archivo de entrada llamado test.scala :

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

Luego compilándolo con scalac -Xprint:parser imprime:

$ 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))))) } }

Para obtener una lista completa de las fases del compilador aplicables a -Xprint:<phase> haga esto:

$ 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

La -Xprint:<phase> también es aplicable a scala y, por lo tanto, a REPL. Sin embargo, también verá todo el código de envoltorio que inserta el 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>


Como ya dije en el otro tema, scalac -print imprime el código de scalac -print , no Java. Traduce todas las palabras clave de Scala que no son directamente compatibles con Java al código de Scala normal. No es posible dejar que el compilador traduzca solo partes de afaik. Pero básicamente una comprensión para siempre se traduce de la misma manera.

Un simple para / rendimiento como este

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

será traducido a

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

Y sin rendimiento

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

a

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

Los fors anidados se traducirán a construcciones planas / mapas anidadas

for(x <- List(1,2,3); y <- List(4,5,6)) yield x*y

será traducido a

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

Así que no hay absolutamente ninguna magia.