Книга: Functional Programming in JavaScript
Назад: Summary
Дальше: B. Glossary of Terms

Appendix A. Common Functions for Functional Programming in JavaScript

This Appendix covers common functions for functional programming in JavaScript:

  • Array Functions:
    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)];   }); };
  • Binding Functions:
    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);
  • Category Theory:
    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))));     };   }; };
  • Composition:
    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));   }; };
  • Currying:
    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([]); };
  • Functors:
    // 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];   }; };
  • Lenses:
    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 );
  • Maybes:
    var Maybe = function(){};  Maybe.prototype.orElse = function(y) {   if (this instanceof Just) {     return this.x;   }   else {     return y;   } };  var None = function(){};  None.prototype = Object.create(Maybe.prototype); None.prototype.toString = function(){return 'None';}; var none = function(){return new None()}; // and the Just instance, a wrapper for an object with a value var Just = function(x){return this.x = x;}; Just.prototype = Object.create(Maybe.prototype); Just.prototype.toString = function(){return "Just "+this.x;}; var just = function(x) {return new Just(x)}; var maybe = function(m){   if (m instanceof None) {     return m;   }   else if (m instanceof Just) {     return just(m.x);   }   else {     throw new TypeError("Error: Just or None expected, " + m.toString() + " given.");    } };  var maybeOf = function(f){   return function(m) {     if (m instanceof None) {       return m;     }     else if (m instanceof Just) {       return just(f(m.x));     }     else {       throw new TypeError("Error: Just or None expected, " + m.toString() + " given.");      }   }; };
  • 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; };
  • Partial Application:
    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));   }; };
  • Trampolining:
    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); };   }; };
  • Type Safeties:
    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-combinator:
    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;   }; };
Назад: Summary
Дальше: B. Glossary of Terms

bsn
thank
Vesa Karvonen
I hope you don't mind, but I’d like to point you and your readers to my high-performance optics library for JavaScript that is in production use in multiple projects, has comprehensive support for partial optics and interactive documentation: https://calmm-js.github.io/partial.lenses/ (this takes a moment to load — be patient!)