Question

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
}
Was it helpful?

Solution

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

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top