js 柯里化Currying
今天读一篇博客的时候,看都有关柯里化的东西,由于好奇,特意查了一下,找到一篇比较好的文章,特意收藏。
引子
先来看一道小问题:
有人在群里出了到一道题目:
var s = sum(1)(2)(3) ....... 最后 alert(s) 出来是6
var s = sum(1)(2)(3)(4) ....... 最后 alert(s) 出来是10
问sum怎么实现?
刚看到题目,我第一反应是sum返回的是一个function,但是没有最终实现,印象中看到过类似的原理,但是记不清了。
后来同事说,这个是叫柯里化,
实现方法比较巧妙:
function sum(x){
var y = function(x){
return sum(x+y)
}
y.toString = y.valueOf = function(){
return x;
}
return y;
}
下面我们就深入来看一下currying柯里化~
什么是柯里化?
柯里化是这样的一个转换过程,把接受多个参数的函数变换成接受一个单一参数(注:最初函数的第一个参数)的函数,如果其他的参数是必要的,返回接受余下的参数且返回结果的新函数。
当我们这么说的时候,我想柯里化听起来相当简单。Javascript中是怎么实现的呢?
假设我们要写一个函数,接受3个参数。
var sendMsg = function (from, to, msg) {
alert(["Hello " + to + ",", msg, "Sincerely,", "- " + from].join("\n"));
}
现在,假定我们有柯里化函数,能够把传统的Javascript函数转换成柯里化后的函数:
var sendMsgCurried = curry(sendMsg);
// returns function(a,b,c) var sendMsgFromJohnToBob = sendMsgCurried("John")("Bob");
// returns function(c) sendMsgFromJohnToBob("Come join the curry party!");
//=> "Hello Bob, Come join the curry party! Sincerely, - John"
手动柯里化
在上面的例子中,我们假定拥有神秘的curry函数。我会实现这样的函数,但是现在,我们首先看看为什么这样的函数是如此必要。
举个例子,手动柯里化一个函数并不困难,但是确实有点啰嗦:
// uncurried
var example1 = function (a, b, c) { // do something with a, b, and c
}; // curried
var example2 = function(a) {
return function (b) {
return function (c) { // do something with a, b, and c
};
};
};
在Javascript,即使你不指定一个函数所有的参数,函数仍将被调用。这是个非常实用Javascript的功能,但是却给柯里化制造了麻烦。
思路是每一个函数都是有且只有一个参数的函数。如果你想拥有多个参数,你必须定义一系列相互嵌套的函数。讨厌!这样做一次两次还可以,可是需要以这种方式定义需要很多参数的函数的时候,就会变得相当啰嗦和难于阅读。(但是别担心,我会马上告诉你一个办法)
一些函数编程语言,像Haskell和OCaml,语法中内置了函数柯里化。在这些语言中,举个例子,每个函数是拥有一个参数的函数,并且只有一个参数。你可能会认为这种限制麻烦胜过好处,但是语言的语法就是这样,这种限制几乎无法察觉。
创建一个curry辅助函数
理论上我们期望可以有一个方便的方式转换普通老式的Javascript函数(多个参数)到完全柯里化的函数。
这个想法不是我独有的,其他的人已经实现过了,例如在wu.js 库中的.autoCurry()函数(尽管你关心的是我们自己的实现方式)。
首先,让我们创建一个简单的辅助函数 .sub_curry:
function sub_curry(fn
/*, variable number of args */
) {
var args = [].slice.call(arguments, 1);
return function () {
return fn.apply(this, args.concat(toArray(arguments)));
};
}
让我们花点时间看看这个函数的功能。相当简单。sub_curry接受一个函数fn作为它的第一个参数,后面跟着任何数目的输入参数。返回的是一个函数,这个函数返回fn.apply执行结果,参数序列合并了该函数最初传入参数的,加上fn调用的时候传入参数的。
看例子:
var fn = function(a, b, c) { return [a, b, c]; }; // these are all equivalent
fn("a", "b", "c");
sub_curry(fn, "a")("b", "c");
sub_curry(fn, "a", "b")("c");
sub_curry(fn, "a", "b", "c")();
//=> ["a", "b", "c"]
很明显,这并不是我门想要的,但是看起来有点柯里化的意思了。现在我们将定义柯里化函数curry:
function curry(fn, length) { // capture fn's # of parameters
length = length || fn.length;
return function () {
if (arguments.length < length) { // not all arguments have been specified. Curry once more.
var combined = [fn].concat(toArray(arguments));
return length - arguments.length > 0
? curry(sub_curry.apply(this, combined), length - arguments.length)
: sub_curry.call(this, combined );
} else { // all arguments have been specified, actually call function
return fn.apply(this, arguments);
}
};
}
这个函数接受两个参数,一个函数和要“柯里化”的参数数目。第二个参数是可选的,如果省略,默认使用Function.prototype.length 属性,就是为了告诉你这个函数定义了几个参数。
最终,我们能够论证下面的行为:
var fn = curry(function(a, b, c) { return [a, b, c]; }); // these are all equivalent
fn("a", "b", "c");
fn("a", "b", "c");
fn("a", "b")("c");
fn("a")("b", "c");
fn("a")("b")("c");
//=> ["a", "b", "c"]
原文地址:http://www.jb51.net/article/81190.htm
js 柯里化Currying的更多相关文章
- JS中的柯里化(currying)
何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名). 柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参 ...
- JS中的柯里化(currying) 转载自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]
JS中的柯里化(currying) by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpr ...
- js的柯里化currying
转载:http://www.zhangxinxu.com/wordpress/2013/02/js-currying/ 我自己的理解柯里化就是这样的,(1)必须返回匿名函数,(2)参数复用. 1. 参 ...
- JS 柯里化 (curry)
用 JS 理解柯里化 函数式编程风格,试图以函数作为参数传递(回调)和无副作用的返回函数(修改程序的状态). 很多语言采用了这种编程风格.JavaScript,Haskell,Clojure,Erla ...
- 柯里化currying + 隐式调用 = 一个有名的add面试题
柯里化 =================================== 维基百科解释: 柯里化,英语:Currying(果然是满满的英译中的既视感),是把接受多个参数的函数变换成接受一个单一参 ...
- 前端开发者进阶之函数柯里化Currying
穆乙:http://www.cnblogs.com/pigtail/p/3447660.html 在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接 ...
- 函数柯里化(Currying)示例
”函数柯里化”是指将多变量函数拆解为单变量的多个函数的依次调用, 可以从高元函数动态地生成批量的低元的函数.可以看成一个强大的函数工厂,结合函数式编程,可以叠加出很BT的能力.下面给出了两个示例,说明 ...
- js柯里化的一个应用
听到同学说面试一道题目 add(1)(2)(3)(4); 查询了下资料 这是一个js里面的柯里化 现象 add_curry防范返回的是一个 retVal,并不是执行结果.这里的代码很想递归,但是不是 ...
- map的实现和柯里化(Currying)
版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/11329874.html 作者:窗户 ...
随机推荐
- xlrd,xlwt操作Excel实例
把有合并单元格的信息读取出来,输出所在层数与位置 我要操作的Excel是这样的 要的到的是这样的效果 # -*- coding: utf-8 -*- import xlrd import xlwt r ...
- nginx3
Yum安装更简单.安装并启动keepalived,表示安装成功.有3个进程. etc\keepalived\keepalived.conf: 备的keepalived配置文件: ! Configura ...
- 【Head First Servlets and JSP】笔记2:MVC迷你教程
1.采用MVC,不仅要求业务逻辑和表示分离.实际上,业务逻辑甚至根本不知道表示的存在.MVC的关键是,业务逻辑要与表示分离,而要求在中间放上别的东西,这样业务逻辑本身就可以作为一个可以重用的Java类 ...
- 08/27 Django admin相关
一.django-admin的简单回顾: admin: Django的后台数据管理的web版本 1.admin a:models.py - 创建表 b:admin.py - 注册表 admin. ...
- openstack认证实践
环境: 客户端:负责发送请求, 服务器:负责接受请求: 认证服务器keystone:负责认证 具体认证步骤: 1.客户端首先进行签名计算,将得到的签名字符串作为authorization发给keyst ...
- QT添加资源文件,并为工具栏添加图片
1.右键工程,添加新文件,QT,QT Resource File. 2.选择res,添加前缀,添加文件,(把图片放在文件夹里,把文件夹放在工程目录下)选择图片 3.在ui中,下方有个Action Ed ...
- linux 压缩以及解压命令
转载:http://blog.csdn.net/mmllkkjj/article/details/6768294/ tar-c: 建立压缩档案-x:解压-t:查看内容-r:向压缩归档文件末尾追加文件- ...
- Floyd算法 - 最短路径
2017-07-27 22:21:04 writer:pprp 该算法的本质是动态规划,形式简单,复杂度高为O(n^3): d[i][j] = max(d[i][k]+d[k][j],d[i][j]) ...
- Linux Wget 命令
Linux wget是一个下载文件的工具,它用在命令行下.对于Linux用户是必不可少的工具,尤其对于网络管理员,经常要下载一些软件或从远程服务器恢复备份到本地服务器.如果我们使用虚拟主机,处理这样的 ...
- tyvj 1055 沙子合并 区间dp经典模型,石子合并
P1055 沙子合并 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 设有N堆沙子排成一排,其编号为1,2,3,…,N(N<=300).每堆沙子 ...