6

我想查看f在 map/flatmap 中传递的函数,但没有运气。我抛出异常以查看任何迹象f,但没有工作。那是什么功能?它是如何在幕后生成的?

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

2 回答 2

11

您理解的等效代码

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

是这样的:

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

您可以使用scalac -Xprint:parser main.scala从您的for-comprehension. 在这种情况下,你会得到这个:

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

你也可以在 REPL 中得到它,而不需要像这样添加宏:

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)))))
于 2014-01-15T14:49:43.443 回答
11

如果您使用的是 Scala 2.10 或更高版本,则可以使用以下内容在 repl 中显示脱糖的 scala 代码:

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

这将允许您传入代码块,并查看它们转换成的内容。对于您的示例,在 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)))))

有点乱,因为 repl 创建了几个中间临时变量,但是你可以看到正在发生的事情的结构。

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

这适用于大多数任何表达式,并允许您检查实际代码在编译期间将转换为什么。

更新

我应该指出我的来源——我的版本是在 github 上的Macrocosm 存储desugar库中找到的函数的略微修改版本。

于 2014-01-15T14:55:27.937 回答