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

我理解柯里化的方式是,如果你有一个带有多个参数的函数,你可以重复地将函数应用于每个参数,直到你得到结果。

所以类似的东西f:(A,B) => C变成了A => f(A,_) => f(B)????

并且 uncurrying 是将这个应用程序合并为一个函数,如下所示:

f:A=>B=>C会是f(A,B)

也许我只是对这里的语法感到困惑,但如果有人能指出我在这里缺少的东西,那就太好了。

谢谢

4

2 回答 2

12

希望这个带有大量评论的完整示例很容易理解。如果您有任何问题,请回复。

您可以通过将其放入 Scala 解释器来执行此代码。

// 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 的函数。”

于 2012-12-10T02:48:42.433 回答
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`)
      }
   }
 }

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

其中(a, b) => f(a)(b)的意思是,“一个有两个参数的函数(a, b),它的返回值是你第一次应用a到 HoF时得到的值f,它返回一个函数,该函数又消耗b来返回一个C”。

这有帮助吗?

于 2012-12-10T02:35:33.827 回答