2012-12-10 55 views
6
執行討好高階函數

我的一個同事給我發了一個問題如下:實施,在斯卡拉

實現上的HOF(高階函數)執行討好,你的函數的 簽名是如下:

def curry[A,B,C](f:(A,B) => C) : A => B => C 

類似地,實現執行uncurrying一個函數,如下所示:

def uncurry[A,B,C](f:A => B => C): (A,B) => C 

我理解currying的方式是,如果您有一個函數需要多個參數,您可以重複將函數應用於每個參數,直到得到結果。

所以沿着f:(A,B) => C線的東西變成A => f(A,_) => f(B) ????

而且uncurrying將這個應用程序整合到一個功能如下:

f:A=>B=>Cf(A,B)

也許我只是被語法這裏混淆,但將是巨大的,如果有人能指出我是缺少在這裏。

謝謝

回答

12

希望這完全曾與一堆意見的例子是容易理解的。如果您有任何疑問,請回復。

您可以通過在斯卡拉解釋刪除它執行該代碼。

// Here's a trait encapsulating the definition your coworker sent. 
trait Given { 
    def curry[A,B,C](f:(A,B) => C) : A => B => C 
    def uncurry[A,B,C](f:A => B => C): (A,B) => C 
} 

object Impl extends Given { 
    // I'm going to implement uncurry first because it's the easier of the 
    // two to understand. The bit in curly braces after the equal sign is a 
    // function literal which takes two arguments and applies the to (i.e. 
    // uses it as the arguments for) a function which returns a function. 
    // It then passes the second argument to the returned function. 
    // Finally it returns the value of the second function. 
    def uncurry[A,B,C](f:A => B => C): (A,B) => C = { (a: A, b: B) => f(a)(b) } 

    // The bit in curly braces after the equal sign is a function literal 
    // which takes one argument and returns a new function. I.e., curry() 
    // returns a function which when called returns another function 
    def curry[A,B,C](f:(A,B) => C) : A => B => C = { (a: A) => { (b: B) => f(a,b) } } 
} 

def add(a: Int, b: Long): Double = a.toDouble + b 
val spicyAdd = Impl.curry(add) 
println(spicyAdd(1)(2L)) // prints "3.0" 
val increment = spicyAdd(1) // increment holds a function which takes a long and adds 1 to it. 
println(increment(1L)) // prints "2.0" 
val unspicedAdd = Impl.uncurry(spicyAdd) 
println(unspicedAdd(4, 5L)) // prints "9.0" 

數值較小的例子如何?

def log(level: String, message: String) { 
    println("%s: %s".format(level, message)) 
} 
val spicyLog = Impl.curry(log) // spicyLog's type is String => Unit 
val logDebug = spicyLog("debug") // This new function will always prefix the log 
           // message with "debug". 
val logWarn = spicyLog("warn") // This new function will always prefix the log 
           // message with "warn". 
logDebug("Hi, sc_ray!") // prints "debug: Hi, sc_ray!" 
logWarn("Something is wrong.") // prints "warn: Something is wrong." 

更新 你回覆詢問「編譯器如何計算表達式,如a => b => f(a,b)」。那麼它不會。至少在你的同事的片段中定義事物的方式,這不會被編譯。但是,通常情況下,如果您看到A => B => C這種形式的意思是「將A作爲參數的函數;它返回一個函數,它將B作爲參數並返回C.」

+0

感謝您的解釋。這是一個非常實用的例子。我只是想弄清楚編譯器如何評估表達式,比如a => b => f(a,b) –

+0

我發佈了一個更新。請讓我知道這是否有幫助。 –

+0

謝謝。現在更清楚了。我將此標記爲答案。 –

8

我不知道我真的明白你的問題 - 除了實際的實現,你想知道什麼?如上所述,它應該是很簡單的:

def curry[A,B,C](f:(A,B) => C): A => B => C = 
    a => b => f(a,b) 

什麼a => b => f(a,b)手段是,「的一個說法,a一個函數,其返回值爲b => f(a,b)這又是,一個參數的函數,b ,它的回報值是你執行的f(a,b)(其類型是C)「

a => b => f(a, b)如果有幫助,可以寫得稍微詳細些?

{ (a: A) => {   // a function of *one* argument, `a` 
     (b: B) => {  // a function of *one* argument, `b` 
     f(a, b)   // whose return value is what you get of you execute `f(a,b)` (whose type is `C`) 
     } 
    } 
} 

(a, b) => f(a)(b)手段「的參數(a, b),其返回值的函數就是你當你第一次申請a到紀念館名人f,它返回一個函數反過來消耗b返回C「。

這有幫助嗎?

+0

我猜想我想知道當你鍵入某物=> b => f(a,b)時究竟發生了什麼? –

+0

@sc_ray我希望額外的解釋有幫助嗎? – Faiz

+1

感謝您的解釋。我只是發現了currying的整個概念相當不簡單,所以我們有一個具有多個參數的函數,並且我們通過將函數重寫爲a => b => f(a,b)來一次推遲函數的執行)?編譯器如何評估表達式,如a => b => f(a,b)? –