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 作者:窗户 ...
随机推荐
- java要注意的问题1
一.优先返回空集合而非null 如果程序要返回一个不包含任何值的集合,确保返回的是空集合而不是null.这能节省大量的”if else”检查. public class getLocationName ...
- LeetCode:逆波兰表达式求值【150】
LeetCode:逆波兰表达式求值[150] 题目描述 根据逆波兰表示法,求表达式的值. 有效的运算符包括 +, -, *, / .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说明: 整数除 ...
- Python框架之Tornado(请求阶段)
上图是tornado程序启动以及接收到客户端请求后的整个过程,对于整个过程可以分为两大部分: 启动程序阶段,又称为待请求阶段(上图1.2所有系列和3.0) 接收并处理客户端请求阶段(上图3系列) 简而 ...
- javascript 中的比较大小,兼 typeof()用法
javascript中的排序: 1.不同类型 比 类型 (字符串 > 数字) 2.同类型:(字符串 比 按字母顺序 )(数字 比 大小) 测试: <!DOCTYPE html> ...
- Django CRM 数据库增删改查
原文链接 http://www.cnblogs.com/yangmv/p/5327477.html
- 【学习ffmpeg】打开视频文件,帧分析,并bmp保存关键帧
http://www.tuicool.com/articles/jiUzua http://blog.csdn.net/code_future/article/details/8646717 主题 ...
- Windows10安装mysql数据库
安装以及配置,参考下面链接 https://www.cnblogs.com/qjoanven/p/7898006.html 碰到的问题: 1. 安装的时候出现 mysql Install/Remove ...
- Windows 修改个性化时间显示
A goal is a dream with a deadline. Much effort, much prosperity. 我感觉我的时间显示不够人性化.不够个性化 修改注册表 我的系统为Win ...
- filebeat配置介绍
Filebeat Prospector filebeat.prospectors: - input_type: log paths: - /var/log/apache/httpd-*.log doc ...
- spring cloud 基本小结
Spring cloud系列十四 分布式链路监控Spring Cloud Sleuth https://blog.csdn.net/hry2015/article/details/78905489 S ...