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

时间:2017-10-10 22:44:44

标签: scala oop apache-spark user-defined-functions scala-collections

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

例如:

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

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

上面,Scala交互式shell表明splitFunction有输入参数String,它返回字符串数组。真正的function1在这里指示什么?

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

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

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

例如:File - 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 []

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

1 个答案:

答案 0 :(得分:5)

没有。 (一般而言)

它说<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

“show function implementation”函数必须1)从JVM中检索实现(我相信有一个API,但它适用于调试器),然后2)将代码反编译为Scala / Java。这本身并非不可能,但我认为没有人做过(而且,为什么你会这样做?)

现在,每个Scala匿名函数都可以只存储其代码并覆盖toString来输出它,但是,再一次,没有理由这样做。即使您希望实现用于调试目的,也可能有源代码,您可以使用类文件中的行号跳转到它,如果您想存储它,它已经存储在类文件中。

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

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
}

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