2012-12-10 58 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)? –