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

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

  • 数组函数:

    ```js 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)]; }); }; ```

  • 绑定功能:

    js 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);

  • 范畴论:

    ```js 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] = typeSafetiesi; } 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)))); }; }; }; ```

  • 成分:

    ```js 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)); }; }; ```

  • 当前:

    js 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([]); };

  • 函子:

    ```js // 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]; }; }; ```

  • 镜片:

    ```js 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:

    js 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; };

  • 部分应用:

    ```js 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)); }; }; ```

  • 蹦床:

    ```js 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); }; }; }; ```

  • 类型安全:

    ```js 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 组合符:

    ```js 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; }; }; ```