Skip to content

Latest commit

 

History

History
284 lines (246 loc) · 6.68 KB

File metadata and controls

284 lines (246 loc) · 6.68 KB

八、附录 a:JavaScript 函数式编程的常用函数

本附录涵盖了 JavaScript 中函数编程的常见功能:

  • 数组函数:

    var flatten = function(arrays) {
      return arrays.reduce( function(p,n){
        return p.concat(n);
      });
    };
    
    var invert = function(arr) {
      return arr.map(function(x, i, a) {
        return a[a.length - (i+1)];
      });
    };
  • 绑定功能:

    var bind = Function.prototype.call.bind(Function.prototype.bind);
    var call = bind(Function.prototype.call, Function.prototype.call);
    var apply = bind(Function.prototype.call, Function.prototype.apply);
  • 范畴论:

    var checkTypes = function( typeSafeties ) {
      arrayOf(func)(arr(typeSafeties));
      var argLength = typeSafeties.length;
      return function(args) {
        arr(args);
        if (args.length != argLength) {
          throw new TypeError('Expected '+ argLength + ' arguments');
        }
        var results = [];
        for (var i=0; i<argLength; i++) {
          results[i] = typeSafeties[i](args[i]);
        }
        return results;
      };
    };
    
    var homoMorph = function( /* arg1, arg2, ..., argN, output */ ) {
      var before = checkTypes(arrayOf(func)(Array.prototype.slice.call(arguments, 0, arguments.length-1)));
      var after = func(arguments[arguments.length-1])
      return function(middle) {
        return function(args) {
          return after(middle.apply(this, before([].slice.apply(arguments))));
        };
      };
    };
  • 成分:

    Function.prototype.compose = function(prevFunc) {
      var nextFunc = this;
      return function() {
        return nextFunc.call(this,prevFunc.apply(this,arguments));
      };
    };
    
    Function.prototype.sequence  = function(prevFunc) {
      var nextFunc = this;
      return function() {
        return prevFunc.call(this,nextFunc.apply(this,arguments));
      };
    };
  • 当前:

    Function.prototype.curry = function (numArgs) {
      var func = this;
      numArgs = numArgs || func.length;
      // recursively acquire the arguments
      function subCurry(prev) {
        return function (arg) {
          var args = prev.concat(arg);
          if (args.length < numArgs) {
            // recursive case: we still need more args
            return subCurry(args);
          }
          else {
            // base case: apply the function
            return func.apply(this, args);
          }
        };
      };
      return subCurry([]);
    };
  • 函子:

    // map :: (a -> b) -> [a] -> [b]
    var map = function(f, a) {
      return arr(a).map(func(f));
    }
    
    // strmap :: (str -> str) -> str -> str
    var strmap = function(f, s) {
      return str(s).split('').map(func(f)).join('');
    }
    
    // fcompose :: (a -> b)* -> (a -> b)
    var fcompose = function() {
      var funcs = arrayOf(func)(arguments);
      return function() {
        var argsOfFuncs = arguments;
        for (var i = funcs.length; i > 0; i -= 1) {
          argsOfFuncs  = [funcs[i].apply(this, args)];
        }
        return args[0];
      };
    };
  • 镜片:

    var lens = function(get, set) {
      var f = function (a) {return get(a)};
      f.get = function (a) {return get(a)}; 
      f.set = set;
      f.mod = function (f, a) {return set(a, f(get(a)))};
      return f;
    };
    
    // usage:
    var first = lens(
      function (a) { return arr(a)[0]; }, // get
      function (a, b) { return [b].concat(arr(a).slice(1)); } // set
    );
  • may:t0]

  • Mixins:

    Object.prototype.plusMixin = function(mixin) {
      var newObj = this;
      newObj.prototype = Object.create(this.prototype);
      newObj.prototype.constructor = newObj;
      for (var prop in mixin) {
        if (mixin.hasOwnProperty(prop)) {
          newObj.prototype[prop] = mixin[prop];
        }
      }
      return newObj;
    };
  • 部分应用:

    function bindFirstArg(func, a) {
      return function(b) {
        return func(a, b);
      };
    };
    
    Function.prototype.partialApply = function(){
      var func = this; 
      args = Array.prototype.slice.call(arguments);
      return function(){
        return func.apply(this, args.concat(
          Array.prototype.slice.call(arguments)
        ));
      };
    };
    
    Function.prototype.partialApplyRight = function(){
      var func = this; 
      args = Array.prototype.slice.call(arguments);
      return function(){
        return func.apply(
          this,
          Array.protype.slice.call(arguments, 0)
        .concat(args));
      };
    };
  • 蹦床:

    var trampoline = function(f) {
      while (f && f instanceof Function) {
        f = f.apply(f.context, f.args);
      }
      return f;
    };
    
    var thunk = function (fn) {
      return function() {
        var args = Array.prototype.slice.apply(arguments);
        return function() { return fn.apply(this, args); };
      };
    };
  • 类型安全:

    var typeOf = function(type) {
      return function(x) {
        if (typeof x === type) {
          return x;
        }
        else {
          throw new TypeError("Error: "+type+" expected, "+typeof x+" given.");
        }
      };
    };
    
    var str = typeOf('string'),
      num = typeOf('number'),
      func = typeOf('function'),
      bool = typeOf('boolean');
    
    var objectTypeOf = function(name) {
      return function(o) {
        if (Object.prototype.toString.call(o) === "[object "+name+"]") {
          return o;
        }
        else {
          throw new TypeError("Error: '+name+' expected, something else given."); 
        }
      };
    };
    var obj = objectTypeOf('Object');
    var arr = objectTypeOf('Array');
    var date = objectTypeOf('Date');
    var div = objectTypeOf('HTMLDivElement');
    
    // arrayOf :: (a -> b) -> ([a] -> [b])
    var arrayOf = function(f) {
      return function(a) {
        return map(func(f), arr(a));
      }
    };
  • y 组合符:

    var Y = function(F) {
      return (function (f) {
        return f(f);
      }(function (f) {
        return F(function (x) {
          return f(f)(x);
        });
      }));
    };
    
    // Memoizing Y-Combinator:
    var Ymem = function(F, cache) {
      if (!cache) {
        cache = {} ; // Create a new cache.
      }
      return function(arg) {
        if (cache[arg]) {
          // Answer in cache
          return cache[arg] ;
        }
        // else compute the answer
        var answer = (F(function(n){
          return (Ymem(F,cache))(n);
        }))(arg); // Compute the answer.
        cache[arg] = answer; // Cache the answer.
        return answer;
      };
    };