Вопрос

I want to see the f function that is getting passed in map/flatmap, but no luck. I threw an an exception to see any sign of f, did not work. What is that function? how is it generated behind the scenes?

Exception in thread "main" java.lang.RuntimeException
   at x.x.Main$A.getInt(Empty.scala:8)
   at x.x.Main$A.flatMap(Empty.scala:10)

object Main extends App {

  class A {
    def getInt: Int = throw new RuntimeException
    def map(f: Int => Boolean): Boolean = f(getInt)
    def flatMap(f: Int => Boolean): Boolean = f(getInt)
  }

  for {
    x <- new A
    y <- new A
  } yield x == y
}
Это было полезно?

Решение

The equivalent code for your for-comprehension

for {
  x <- new A
  y <- new A
} yield x == y

is like this:

new A().flatMap{ x => new A().map{ y => x == y } }

You could use scalac -Xprint:parser main.scala to get code generated from your for-comprehension. In this case you'll get this:

new A().flatMap(((x) => new A().map(((y) => x.$eq$eq(y)))))

You could also get it in REPL without addition macro like this:

import reflect.runtime.universe._

show{ reify{
  for {
    x <- new A
    y <- new A
  } yield x == y
}.tree }
// new $read.A().flatMap(((x) => new $read.A().map(((y) => x.$eq$eq(y)))))

Другие советы

If you're using Scala 2.10 or higher, you can use the following to show desugared scala code in the repl:

import scala.reflect.macros.Context // use BlackboxContext if you're in 2.11
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): Unit = macro _desugar

This will allow you to pass in blocks of code, and see what they translate into. For your example, in the repl:

scala> class A {
     |   def getInt: Int = throw new RuntimeException
     |   def map(f: Int => Boolean): Boolean = f(getInt)
     |   def flatMap(f: Int => Boolean): Boolean = f(getInt)
     | }
defined class A

scala> desugar {
     |   for {
     |     x <- new A
     |     y <- new A
     |   } yield x == y
     | }
new $line15.$read.$iw.$iw.$iw.$iw.A().flatMap(((x: Int) => new $line15.$read.$iw.$iw.$iw.$iw.A().map(((y: Int) => x.==(y)))))

It's a bit messy, because the repl creates several intermediate temporary variables, but you can see the structure of what's happening.

new A().flatMap { (x: Int) =>
  new A().map { (y: Int) =>
    x == y
  }
}

This works for most any expression, and lets you inspect what the actual code will translate to during compilation.

Update

I should point out my source - my version of desugar is a slightly modified version of a function found in the Macrocosm repo on github.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top