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的例子。
     
  • 相关阅读:
    WikiPedia技术架构学习笔记
    MySQL 架构设计篇 (十二) 可扩展设计的基本原则
    php前端控制器二
    php前端控制器三
    构建可扩展的WEB站点读书笔记
    发布脚本开发框架代码
    改良dbgrideh的文字过滤
    cxgrid在当前View插入记录
    生成不重复单据编号
    cxgrid按条件计算合计值
  • 原文地址:https://www.cnblogs.com/cypine/p/3258552.html
Copyright © 2011-2022 走看看