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 作者:窗户 ...
随机推荐
- mybatis 插入之后返回id
usermapper.xml <insert id="insert" parameterType="app.models.User" keyPropert ...
- cdoj1338郭大侠与英雄学院
地址:http://acm.uestc.edu.cn/#/problem/show/1338 思路: 郭大侠与英雄学院 Time Limit: 6000/2000MS (Java/Others) ...
- unbntu修改mac地址
分享下Ubuntu下更改MAC地址的简单方法: 首先把网卡设备给 down 掉,否则会报告系统忙,无法更改. sudo ifconfig eth0 down 然后修改 MAC 地址,这一步较 Wind ...
- 搭建 Spring 开发环境
把以下 jar 包加入到工程的 classpath 下: Spring 的配置文件: 一个典型的 Spring 项目需要创建一个或多个 Bean 配置文件, 这些配置文件用于在 Spring IOC ...
- SpringBoot2.0整合Sharding-Jdbc
maven: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spri ...
- 并发-AtomicInteger源码分析—基于CAS的乐观锁实现
AtomicInteger源码分析—基于CAS的乐观锁实现 参考: http://www.importnew.com/22078.html https://www.cnblogs.com/mantu/ ...
- Google maps API
https://developers.google.com/kml/documentation/kml_tuthttps://developers.google.com/maps/documentat ...
- 有关写log的思考
前言 在软件开发过程中,log往往是不太引人注意的环节,大部分的log都只是开发人员为了调试bug临时加上的.这样出来的软件,最后的log往往杂乱无章没有系统性.我们判断一个软件系统的log写的好不好 ...
- thinkPHP中怎么使用阿里云的sdk
使用阿里云官方给的方法总会报错 Class 'Home\Controller\DefaultProfile' not found 这样是因为namespace的原因,将aliyun sdk 放在con ...
- 端口被sysmtem占用
今天启动Apache的时候老是提示失败,很简单,使用 netstat -ano 发现80端口被占用.如图所示: