函数柯里化(Currying)和偏函数应用(部分应用函数)(Partial Application)的比较
【名词解释】Currying:因为是美国数理逻辑学家哈斯凯尔·加里(Haskell Curry)发明了这种函数使用技巧,所以这样用法就以他的名字命名为 Currying,中文翻译为“柯里化”。
我感觉很多人都对函数柯里化(Currying)和偏函数应用(Partial Application)之间的区别搞不清楚,尤其是在相似的上下文环境中它们同时出现的时候。
偏函数解决这样的问题:如果我们有函数是多个参数的,我们希望能固定其中某几个参数的值。
几乎所有编程语言中都有非常明显的偏函数应用。在C语言中:
int foo (int a, int b, int c) {
return a + b + c;
}
int foo23(int a, int c) {
return foo (a, 23, c);
}
foo23 函数实际上就是一个 foo 函数的偏函数应用,参数 b 的值被固定为 23。
当然,像这样明显的偏函数并没有太大的用处;我们通常会希望编程语言能提供我们某些偏函数特征。
例如,在 Python 语言中,我们可以这样做:
from functools import partial
def foo (a,b,c):
return a + b + c
foo23 = partial (foo, b=23)
foo23(a = 1, c = 3) # => 27
函数柯里化(Currying)明显解决的是一个完全不同的问题:如果我们有几个 单参数 函数,并且这是一种支持一等函数(first-class)的语言,如何去实现一个多参数函数?函数柯里化是一种 实现多参数函数的方法。
下面是一个单参数的 Javascript 函数:
var foo = function(a) {
return a * a;
}
如果我们受限只能写单参数函数,可以像下面这样模拟出一个多参数函数:
var foo = function(a) {
return function(b) {
return a * a + b * b;
}
}
通过这样调用它: (foo (3))(4) ,或直接 foo (3)(4) 。
注意,函数柯里化提供了一种非常自然的方式来实现某些偏函数应用。如果你希望函数 foo 的第一个参数值被固定成5,你需要做的就是 var foo5 = foo (5) 。这就 OK 了。函数 foo5 就是 foo 函数的偏函数。注意,尽管如此,我们没有很简单的方法对 foo 函数的第二个参数偏函数化(除非先偏函数化第一个参数)。
当然,Javascript 是支持多参数函数的:
var bar = function(a, b) {
return a * a + b * b;
}
我们定义的 bar 函数并不是一个柯里化的函数。调用 bar (5) 并不会返回一个可以输入 12 的函数。我们只能像 bar (5,12) 这样调用这个函数。
在一些其它语言里,比如 Haskell 和 OCaml,所有的多参数函数都是通过柯里化实现的。
下面是一个把上面的 foo 函数用 OCaml 语言写成的例子:
let foo = fun a ->
fun b ->
a * a + b * b
下面是把上面的 bar 函数用 OCaml 语言写成的例子:
let bar = fun a b ->
a * a + b * b
头一个函数我们叫做“显式柯里化”,第二个叫做“隐式柯里化”。
跟 Javascript 不一样,在 OCaml 语言里, foo 函数和 bar 函数是完全一样的。我们用完全一样的方式调用它们。
# foo 3 4;;
- : int = 25
# bar 3 4;;
- : int = 25
两个函数都能够通过提供一个参数值来创造一个偏函数:
# let foo5 = foo 5;;
val foo5 : int -> int = <fun>
# let bar5 = bar 5;;
val bar5 : int -> int = <fun>
# foo5 12;;
- : int = 169
# bar5 12;;
- : int = 169
事实上,我们可以把下面这个匿名函数:
fun arg1 arg2 ... argN -> exp
当作是下面这个函数的简写:
fun arg1 -> fun arg2 -> ... -> fun argN -> exp
函数柯里化和偏函数应用的总结
偏函数应用是找一个函数,固定其中的几个参数值,从而得到一个新的函数。 函数柯里化是一种使用匿名单参数函数来实现多参数函数的方法。 函数柯里化能够让你轻松的实现某些偏函数应用。 有些语言(例如 Haskell, OCaml)所有的多参函数都是在内部通过函数柯里化实现的。
- CSS Auto Reload:解放F5 键,自动刷新浏览器的前端利器(Chrome 扩展)
- zepto 基础知识(3)
- 1.[Andriod]之Andriod布局 VS WinPhone布局
- WordPress自定义url 中的“author” 别名
- ASP.NET 4 AppFabric 输出缓存提供程序
- WordPress 中禁止编辑“已发布”的文章
- Windows Server 2008 R2 网络负载平衡 (NLB)资料汇总
- 0.[Andriod]之从零安装配置Android Studio并编写第一个Android App
- WordPress 后台编辑文章页面添加自定义提示文字
- 使用json 和jQuery制作级联dropdownlist
- 在64位Windows 7/2008操作系统上部署32位的Web应用程序错误
- 云计算浪潮
- 2.[Andriod]Andriod Studio结合Visual Studio Emulator for Android调试Android App
- Windows Server AppFabric Caching
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 七日Python之路--第四天(之多线程)
- 超性感的React Hooks(八)useContext
- 七日Python之路--第三天(之不安分 wxPython)
- 七日Python之路--第三天
- 超性感的React Hooks(九)useContext实践
- 七日Python之路--第三天(之初试Django 2-2)
- 超性感的React Hooks(十)useRef
- 七日Python之路--第三天(之初试Django 2-1)
- 超性感的React Hooks(十一)useCallback、useMemo
- 七日Python之路--第二天
- 八、通过断点调试观察JS执行过程
- 传智播客OA项目学习--阶段三(Struts中Action书写)
- 九、函数与函数式编程
- 关于Hibernate懒加载----Spring filter
- 十、详解函数柯里化