2017-09-12 70 views
5

任何人都可以提供關於如何通過Scala編譯器將名稱參數=> TFunction0參數() => T轉換爲另一個的權威答案嗎?我知道它們並不相同,但差別非常微小,因爲它們可以在許多場景中互換使用。Scala:函數0與名稱參數

示例:如果我定義

def someFunction: Int = 2 
def f(x: => Int): Unit = println(x) 

然後我可以成功地調用

f(2) 
f(someFunction) 

如何是() => Int用於=> Int可接受的置換?

更一般地說,() => T是一個普遍接受的替代名稱爲=> T的參數嗎?

另外,請糾正我,如果我錯了以下的理由:=> T是從不爲() => T可接受的替代,因爲第一個是值類型(T),另一種是功能型。也就是說,如果我有def f(x:() => Int),我將永遠無法通過Int或懶惰Int(因爲沒有懶惰類型,所以甚至沒有意義)。

+5

你的例子絕對*不*等價。第一個產生一個'Try [()⇒Int]',第二個'Try [Int]'。 '()⇒Int'的函數參數被轉換爲'⇒T',其中'T'爲'()⇒Int'。 –

+0

這裏有一些很好的信息:https://tpolecat.github.io/2014/06/26/call-by-name.html – nevets1219

+0

它們不會相互替換,它們也不會被Scala編譯器轉換爲另一個。它們只是不同的東西,通常用於不同的目的。 –

回答

3

好的,這裏是完整的細分。

def value: Int = ??? 
def method(): Int = ??? 

def f1(f:() => Int) = ??? 
def f2(f: => Int) = ??? 

f1(value) // fails 
f1(method) // works 
f2(value) // works 
f2(method) // works with a warning "empty-paren method accessed as parameterless" 
  1. F1(值)

因爲f1期待一個單位=> Int函數,但是未給出一個Int值這一個失敗。

  • F1(方法)

  • 這一個工作,因爲f1期待的功能,並且被給予的方法。以下是區別:方法在Scala中不是一個值;它不能獨立存在,並且是它在(類,特徵,對象等)中定義的上下文的屬性。函數是一個值;它可以保存在一個集合中,作爲另一個函數的參數,從一個函數返回等等。當編譯器期待一個函數並給出一個方法時,它將執行eta expansion。給定一個函數f: (a: Int, b: Int) => Int,eta擴展是在保留簽名的同時創建另一個層的過程,因此它變成(a: Int, b: Int) => f(a, b)。這種技術很有用,因爲我們可以將方法轉換爲函數。給定一些方法def f(a: Int): Int = ???,我們可以執行eta-expansion來創建類型爲Int => Int的函數:(a: Int) => f(a)。如果你有興趣,我前一段時間寫了一個關於這個的blog post

  • F2(值)

  • 作品沒有驚喜,但要注意的是,傳遞的值被訪問每它在所用時間的事實功能體。

  • F2(方法)

  • 工程,但與我們所調用的方法是通過使用與空括號限定的警告無插入語。好的做法是在它們只是表示一個值時使用沒有括號的方法(例如f),但是每次訪問它時都會重新計算一個值,例如,當執行某種副作用並因此該方法不是冪等的時,使用帶有空括號的方法(例如f())。 createSnapshot()(同樣,這不應該出現在純功能代碼中)。

    建議的意思:不要用什麼替代什麼,不要使用替換品。如果某件事需要一個功能,請爲它提供一個功能。如果它需要一個值,請提供一個值。如果一個方法沒有parens定義,調用它沒有parens。如果它有parens,請用parens調用它。

    如果你需要從一個方法到另一個功能並且編譯器期望一個函數,eta-expansion將自動發生。如果它不期待功能,則需要手動完成。

    def f(): Int = ??? 
    val a = f    // no function context; a is a string 
    val b:() => Int = f // b is a function Unit => Int 
    val c = f2 _   // c is a function Unit => Int 
    

    最後一種情況下是一個部分應用功能。我覺得我現在過於寬泛,所以我會停下來。我希望這有助於。