zoukankan      html  css  js  c++  java
  • 偏函数应用(Partial Application)和函数柯里化(Currying)

    偏函数应用指的是固化函数的一个或一些参数,从而产生一个新的函数。比如我们有一个记录日志的函数:

       1:  def log(level, message):
       2:      print level + ": " + message
       3:   
       4:  #usage
       5:  log("Warning", "this is one warning message")
       6:  log("Error", "this is one error message")

    在这个函数基础上我们可以固化level参数,产生新的具有特定意义的log函数:

       1:  def logWarning(message):
       2:      log("Warning", message)
       3:   
       4:  def logError(message):
       5:      log("Error", message)
       6:   
       7:  #usage
       8:  logWarning("this is one warning message")
       9:  logError("this is one error message")

    这就叫偏函数应用。

    在Python中可以借助functools模块来完成偏函数应用,而不用手工编写代码。

       1:  from functools import partial
       2:   
       3:  logWarning = partial(log, "Warning")
       4:   
       5:  #usage
       6:  logWarning("this is one warning message")

    partial是一个高阶函数(参数含有函数类型,返回值也是函数类型),所以对于3个或更多参数的函数我们还可以这样用:

       1:  def log(level, message, stack):
       2:      print level + ": " + message
       3:      print stack
       4:   
       5:  logUnknownError = partial(partial(log, "Error"), "Unknown")
       6:  logUnkownError("stack content")
       7:   
       8:  #output
       9:  #Error: Unkown
      10:  #stack content

    Currying指的是将一个具有多个参数的函数,转换成能够通过一系列的函数链式调用,其中每一个函数都只有一个参数。我们对log函数进行Currying:

       1:  def log(level):
       2:      def logMessage(message):
       3:          print level + ": " + message
       4:   
       5:      return logMessage
       6:   
       7:  #usage
       8:  log("Warning")("this is one warning message")
       9:   
      10:  #or like this
      11:  logError = log("Error")
      12:  logError("this is one error message")
    对于curried函数是不能使用多参数的调用方式:
    log(“warning”, “this is one warning message”)
    这样会得到错误,因为log只接受一个参数。
    偏函数和Currying看起来有点类似,区别是什么呢?偏函数是用特定的值来具体化参数,而Currying是变成了一条函数链。
       1:  from functools import partial
       2:   
       3:  def log(level, message, stack):  
       4:        print level + ": " + message
       5:        print stack   
       6:        
       7:  #partial application
       8:  partialLogWarning = partial(log, "Warning")
       9:   
      10:  #currying
      11:  def curriedLog(level):
      12:      def logMsg(message):
      13:            def logStack(stack): 
      14:                print level + ": " + message
      15:                print stack
      16:   
      17:            return logStack
      18:   
      19:      return logMsg
      20:      
      21:  curriedLogWarning = curriedLog("Warning")
      22:   
      23:  #1. 偏函数后依然可以使用多参数,只要还有参数未固化;而Currying只能使用函数链
      24:  #work  
      25:  partialLogWarning("message", "stack")
      26:  curriedLogWarning("message")("stack")
      27:   
      28:  #2. Currying得到简化的函数方式更自然,而偏函数必须借用高阶函数或手动生成
      29:  curriedLogError  = curriedLog("Error")
      30:  curriedLogUnknownError = curriedLog("Error")("Unknown")
      31:  curriedLogUnknownError2 = curriedLogError("Unknown")
      32:   
      33:  partialLogError = partial(log, "Error")
      34:  partialLogUnknownError = partial(log, "Error", "Unknown")
      35:  partialLogUnknownError2 = partial(partial(log, "Error"), "Unknown")
     
    偏函数和Currying有什么用?主要就是从能一个通用函数得到更特定的函数。有一些编程经验的,一定都手工写过偏函数应用吧。
    Currying提供了另外一种实现方式。这种方式在函数式编程中更常见。函数式编程思想,不仅在Lisp这样的函数式编程语言中,在更多的语言中也得到了实现和发展,像Python,Javascript乃至C#这样的命令式语言(imperative language)。所以有机会不妨考虑下使用Currying,能否更好地解决问题。
     
    延伸阅读
    1. http://mtomassoli.wordpress.com/2012/03/18/currying-in-python/, Python中的Partial Application和Currying,里面实现了一个函数,能把普通函数转换成Curried函数。就像Partial一样能把普通函数进行偏函数应用。
    2. http://www.aqee.net/currying-partial-application/,这篇文章中有javascirpt的例子。
     
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    现在使用控件, 更喜欢继承(覆盖控件已有的函数,很奇怪的一种使用方式)
    Controls 属性与继承 TShape 类的小练习(使用TShape可以解决很多图形问题)
    QT创建窗口程序、消息循环和WinMain函数(为主线程建立了一个QEventLoop,并执行exec函数)
  • 原文地址:https://www.cnblogs.com/cypine/p/3258552.html
Copyright © 2011-2022 走看看