是否可以在 Scala 中打印函数的定义

Is it possible to print definition of a function in Scala

我想知道我们是否可以在 Scala 中打印函数的定义。在 Scala 中,函数被视为对象。

例如:

scala> val splitFunction = (value : String) => { value.split(" ")}

splitFunction: String => Array[String] = <function1>

上面,Scala interactive shell 表示 splitFunction 有输入参数 String 并且它是 returns 字符串数组。 function1 在这里到底指的是什么?

是否可以打印或检索 splitFunction 的定义?

我们可以在 python 中实现同样的效果: Is it possible to print a function as a string in Python?

更新: 在 Apache Spark 中,RDD 沿袭或 DAG 存储有关每个阶段的父 RDD 和转换的信息。我对获取用作 flatMap 或 map 等转换参数的函数(甚至是 lambda 或匿名函数)的定义很感兴趣。

例如:文件 - DebugTest.scala

val dataRDD = sc.textFile( "README.md" )
val splitFunction = (value : String) => {value.split(" ")}
val mapRDD = dataRDD.map(splitFunction )

println(mapRDD.toDebugString)

输出:

(1) MapPartitionsRDD[2] at map at DebugTest.scala:43 []
 |  README.md MapPartitionsRDD[1] at textFile at DebugTest.scala:41 []
 |  README.md HadoopRDD[0] at textFile at DebugTest.scala:41 []

从上面的输出中,我可以理解执行了哪些转换,但无法理解或检索在 "map" 转换中用作参数的 splitFunction 的定义。有没有办法检索或打印它?

没有。 (一般)

它说 <function1> 的原因是因为没有给出一个函数的良好字符串表示,所以我们只是说它是一个接受一个参数的函数。

你无法获取函数定义的原因是因为 Scala 是编译过的。您的函数的 JVM 字节码已经很难读了(当然是我的评论)

aload_1           // Load the second argument (of reference type) onto the stack (the first is this function object)
checkcast #mm     // Where mm is an index into the class constant pool, representing a reference to the class String (cast inserted because this is a generic method)
ldc #nn           // Where nn is an index representing the string " "
invokevirtual #oo // Where oo is another index, this time representing String::split
areturn           // Return whatever's left on the stack

A "show function implementation" 函数必须 1) 从 JVM 中检索实现(我相信有一个 API,但它是为调试器准备的),然后 2) 反编译代码至 Scala/Java。这本身并非不可能,但我认为没有人做到过(真的,为什么 你会这样做?)

现在,每个 Scala 匿名函数都可以只存储其代码并覆盖 toString 以输出它,但是,同样,没有理由这样做。即使你想要调试目的的实现,你很可能有源代码,你可以使用 class 文件中的行号跳转到它,如果你想存储它,它已经存储在 class 文件.

如果您真的想要它,理论上可以定义(选择加入)宏(甚至是编译器插件)

import language.experimental.macros
import reflect.macros.whitebox.Context
def stringF(f: Any): Any = macro stringF_impl
def stringF_impl(c: whitebox.Context)(f: c.Tree): c.Tree = ???

那转

stringF { arg => body } // BTW: say bye to type inference

进入

new Function1[A, R] {
  override def apply(arg: A) = body
  override def toString() = "{ arg => body }" // This part is not there normally
}

但是,再说一遍,我还没有听说有人这样做过,也没有充分的理由去尝试。