2015-12-09 50 views
0

我正在開發Coursera的Scala課程的任務並且有一個問題。出於好奇,我已經從一個匿名函數轉換到一個定義:scala中的高階函數奇怪的參數

object sets { 
    def main(args:Array[String]) { 
    type Set = Int => Boolean 
    def contains(s: Set, elem: Int): Boolean = {println("in contains elem ="+elem);s(elem)} 
    def singletonSet(elem: Int): Set = {  //println("in singleton elem ="+elem); (x: Int) => x == elem} 

     def singletonSetF(x: Int): Boolean = { 
     println ("in singleton elem ="+elem+", x="+x) 
     elem == x 
     } 
     singletonSetF 
    }  
    println(contains(singletonSet(69), 6)) 
    } 
} 

這裏是輸出:

中包含

ELEM = 6

在單ELEM = 69,X = 6

false

我相信代碼是正確的並且正常工作。我的問題是如何以及爲什麼從contains方法傳遞的「elem = 6」參數,在singletonSetF方法中被賦值爲「x = 6」?包含函數調用「(elem)」調用singletonSetF而不是singletonSet?

回答

1

contains函數有兩個參數:一個SetInt。我們正試圖測試Set是否包含Int

Set實際上是Int => Boolean類型的函數,如Set的類型別名所定義。

我們通過調用singletonSet來創建第一個參數,該函數返回一個函數(singletonSetF)。然而,singletonSetF是一個封閉 - 它抓住傳遞到singletonSet的的elem值,在這種情況下是69

最後我們調用s(elem)s是包含值69的閉包。elem是值6,然後綁定到singletonSetF中的參數'x'。

重要:該代碼是一個有點混亂,因爲你用elem是指在兩個不同的地方兩個不同的東西 - 在contains,這是我們爲集的成員資格測試值;在singletonSet中,它是Set的唯一成員。重命名其中的一個可能會有很大幫助!

+0

感謝您的回答。由於我的奴隸剪裁和粘貼原始作業,elem的兩種用法令人困惑。有關閉包的維基百科是一些有趣和實用的例子的另一個很好的資源。 –

1

我認爲主要的問題是,你認爲一個Set是一種固定的數據結構,一旦你從singletonSet獲得它。但是,它只是一個可以調用的函數。 s(elem)調用它並最終執行singletonSetF中的代碼。

這裏發生了什麼:singletonSet(69)調用singletonSet函數。該函數返回singletonSetF函數的函數值。函數值充當一種本地函數或方法的包裝。你看不到包裝,但它隱式添加,因爲singletonSetF不能直接返回(這是一個本地函數,不能傳遞)。

contains收到此功能值,該值正確輸入爲Int => Boolean,並調用值爲6的函數。函數值/ wrapper然後調用值爲6的實際singletonF

1

singletonSetF呼叫,當與值69稱爲在singletonSet方法制造,導致Set實例,它在此情況下是從IntBooleanInt => Boolean)的函數的一個實例。該功能在此處創建(雖然它的值69elem「關閉」),未評估,因此x尚未在此處設置。

然後,當contains被調用,它運行線路s(elem)其中elem這裏(不一樣的elem通過singletonSetF!關閉了)是放慢參數值6

s(elem)是早先創建的函數的調用(s這裏是相同的Set - 因此具有相同Int => Boolean實例 - 通過調用singletonSet創建的),傳遞參數elem(在至contains傳遞的值作爲值6)。

在這一點上,該功能被執行,x = 6,產生您觀察到的打印語句。