3

我想知道我們是否可以在Scala中打印函數的定義。一個函數被視爲Scala中的一個對象。是否可以在Scala中打印函數的定義

例如:

階> VAL splitFunction =(值:字符串)=> {value.split(」「)}

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

以上,Scala的交互式shell表示splitFunction具有輸入參數字符串,它返回字符串數組。真正的功能1在這裏表示什麼?

是否可以打印或檢索splitFunction的定義?

我們可以實現在同一蟒: Is it possible to print a function as a string in Python?

更新: 在Apache的星火,RDD血統或DAG存儲有關在每個階段父RDD和轉換信息。我有興趣獲取一個函數的定義(甚至是lambda函數或匿名函數),用作flatMap或map等變換的參數。

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

從上面的輸出中,我能理解進行什麼變革,但無法理解或用作splitFunction定義檢索「地圖」變換中的一個參數。有沒有辦法檢索或打印它?

回答

4

號(一般)

它之所以說<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「顯示功能實現」功能,就必須1)檢索的JVM實現(我相信有一個API爲,但它意味着調試器),然後2)將代碼反編譯爲Scala/Java。這不是不可能的,本身,但我不認爲任何人都做到了(真的,爲什麼你會怎麼做呢?)現在

,將有可能爲每斯卡拉匿名函數來只存儲其代碼和覆蓋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 
} 

但同樣,我還沒有聽說有人做,並且有沒有理由嘗試。

+0

謝謝你的詳細回覆。欣賞它。我已經用目標和其他信息更新了我的問題。讓我知道你是否有任何解決方案來實現相同的目標。 – aagora

+0

我強烈不同意你的推理。斯卡拉不是「編譯」的。 Scala是一種編程語言。沒有像「編譯的編程語言」這樣的東西。編程語言不被編譯或解釋。編程語言*是*。彙編和解釋是編譯器或解釋器(杜)的特點,而不是語言。每種語言都可以編譯,每種語言都可以解釋。 Scala恰好具有一些編譯實現的事實與您是否可以訪問函數的源代碼無關。無論您使用解釋器還是編譯器來存儲源代碼,您都可以存儲函數的源代碼... –

+0

...。如果Scala語言規範要求函數具有'toSource'方法,那麼編譯器會簡單地使用'toSource'方法生成一個匿名類,該方法將函數的源代碼作爲靜態字符串常量進行包含。例如,所有現有的主流ECMAScript實現都已編譯完畢,但它們都可以打印函數的源代碼,僅僅是因爲ECMA-262規範說他們必須這樣做。 –

相關問題