【问题标题】:Implementing a higher order function that performs currying in scala实现一个在scala中执行currying的高阶函数
【发布时间】:2012-12-10 01:22:40
【问题描述】:

我的一个同事给我发了如下问题:

实现一个执行柯里化的 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)

也许我只是被这里的语法弄糊涂了,但如果有人能指出我在这里遗漏的东西,那就太好了。

谢谢

【问题讨论】:

    标签: scala currying higher-order-functions


    【解决方案1】:

    希望这个包含大量 cmets 的完整示例很容易理解。有问题请回复。

    您可以通过将其放入 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) 等表达式。”好吧,它没有。至少在你同事的 sn-p 中定义的方式是无法编译的。不过,一般来说,如果你看到 A => B => C 形式的东西,它的意思是“一个以 A 作为参数的函数;它返回一个以 B 作为参数并返回 C 的函数。”

    【讨论】:

    • 感谢您的解释。这是一个非常务实的例子。我只是想知道编译器如何评估表达式,例如 a => b => f(a,b)
    • 谢谢。现在清楚多了。我将此标记为答案。
    • 很高兴为您提供帮助。祝你在学习函数式编程的旅途中好运。
    • @sc_ray 啊,看起来这个答案成功了。总是很高兴知道少一个人在探索 FP 时少了一个问题!祝你好运!
    【解决方案2】:

    我不确定我是否真的理解您的问题 - 除了实际实施之外,您还想知道什么?如上所述,它应该是非常简单的:

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

    a => b => f(a,b) 的意思是,“one 参数的函数,a,其返回值是 b => f(a,b),这又是 one 的函数参数,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"。

    这有帮助吗?

    【讨论】:

    • 我想我想知道当你输入 a => b => f(a,b) 时究竟会发生什么?
    • @sc_ray 希望补充说明有帮助?
    • 感谢您的解释。我只是发现整个柯里化概念相当迷幻,所以我们有一个具有多个参数的函数,我们通过将函数重写为 a => b => f(a,b )?编译器如何评估 a => b => f(a,b) 之类的表达式?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-01
    • 2019-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-03
    相关资源
    最近更新 更多