zoukankan      html  css  js  c++  java
  • 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("
    "));
    }

    现在,假定我们有柯里化函数,能够把传统的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

  • 相关阅读:
    进阶系列(8)——匿名方法与lambda表达式
    进阶系列(3)—— 序列化与反序列化
    进阶系列(4)——扩展方法
    数据库设计开发规范
    .Net 项目代码风格
    用JS获取地址栏参数的方法(超级简单)
    Ajax轮询 select循环输出
    【Jquery】jquery刷新页面(局部及全页面刷新)
    网页上 滚动代码 最简单的
    eazyui 或bootstrap table表格里插入图片,点击查看大图
  • 原文地址:https://www.cnblogs.com/web-fusheng/p/6801371.html
Copyright © 2011-2022 走看看