函数curry化(Haskell Curry)

个人白话文对curry化的解释:“当一个函数fn有多个参数时,可以先传入一部分参数,生成一个中继函数nextFn,然后在nextFn当中再传入剩下的参数。(一步curry化)。” 看完curry化,第一个感觉是好高大阿,但是...好像目前没感觉到它有什么用耶。。。然而你并不知道什么时候就会用到它!

Posted by elson on July 12, 2015

什么是函数curry化?

官方解释 柯里化(Currying),又称部分求值(Partial Evaluation),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

个人白话文理解

当一个函数fn有多个参数时,可以先传入一部分参数,生成一个中继函数nextFn,然后在nextFn当中再传入剩下的参数。(一步curry化)

function currying(x, y) {
    if (typeof y == 'undefined') {
        return function (y) {
            return x + y;
        };
    }
    else {
        return x + y;
    }
}

var nextFn = currying(5);
console.log(nextFn(5)); // 10

通用curry化函数

function currying(fn) {
    var slice = Array.prototype.slice;
    // 将arguments对象数组化,并排除第一个参数fn
    var args = slice.call(arguments, 1);

    return function () {
        var newArgs = slice.call(arguments);

        return fn.apply(null, args.concat(newArgs));
    };
}
// test
function add(a, b, c, d, e) {
    return a + b + c + d + e;
}

// 一步curry化
var next = currying(add, 11, 22);
// 两步curry化
var next2 = currying(next, 33);
// 三步curry化
var next3 = currying(next2, 44);

next(33, 44, 55); // 165
next2(44, 55); // 165
next3(55); // 165

curry化有什么用

参照:http://www.zhangxinxu.com/wordpress/2013/02/js-currying/

1. 参数复用

curry化之后会返回一个新的函数,这个函数通过闭包保存着重复的参数。

2. 延迟执行

其实ES5当中的Function.prototype.bind方法运用的就是curry化的思想

if (typeof Function.prototype.bind == 'undefined') {
    Function.prototype.bind = function (o) {
        var me = this;
        var args = [].slice.call(arguments, 1);

        return function () {
            var newArgs = [].slice.call(arguments);

            return me.apply(o, args.concat(newArgs));
        };
    };
}

总结

看完curry化,第一个感觉是好高大阿,但是…好像目前没感觉到它有什么用耶。。。

其实我觉得张鑫旭的博客JS中的柯里化当中,有段话讲的挺有道理的

最近在看《JavaScript模式》一书,天哪,里面出现的各种设计模式(如工厂模式、外观模式、观察者模式),一双手都数不过来。而且这些名词又很抽象,书一合,马上大眼瞪小眼了。这种感觉就像是,房间里来了10个黑人,每个黑人都有一个“¥%#…¥”的名字,好不容易勉强记住了,灯一关房间一黑,等再开灯的时候,每个黑人的名字都变成…..”hello”了。

其实这些模式在实际使用的时候,或多或少都使用过,当看到“xx模式”概念的时候,我们就会猛然惊起:“哦,原来这个就叫做‘观察者模式’等”。现在要讨论的问题是,我们有没有必要把这些“xx模式”都记住呢,都理解其对应的核心呢?

这个问题类似于,我可以看懂NBA的篮球比赛,那我有没有必要把各个球队以及球队的队员都记住呢? 如果想成为JS大神,从这个目标来看,这是需要的;好比优秀的篮球解说员必须要知道每个球队的名字、球员甚至周边八卦。但是,现实很重要。如果连JS函数相关的基本东西都驾驭不好,显然,硬是啃这些似懂非懂的概念只会造成混乱。如果你觉得可以更近一步,先通透几个自己习惯的熟悉的使用模式,足够应付实际项目;其他一些概念什么的,更多的只是噱头,实用性其实并不大。

正如本文的柯里化,看上去很高级,似乎也有点用处,然而JS的灵活性使得很多实现完全摆脱“柯里化”这个概念的束缚,以更通俗易懂的方式实现。 然而,即使实用性不高,我们还是要有所了解,因为,你不知道什么时候会用到它。比方说CSS中的 display:table; 某些情况下可以解决一些棘手问题(secret!)。

因此,本文的柯里化至少要知道个大概…