curry.js 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // wrapped by build app
  2. define("dojox/lang/functional/curry", ["dijit","dojo","dojox","dojo/require!dojox/lang/functional/lambda"], function(dijit,dojo,dojox){
  3. dojo.provide("dojox.lang.functional.curry");
  4. dojo.require("dojox.lang.functional.lambda");
  5. // This module adds high-level functions and related constructs:
  6. // - currying and partial functions
  7. // - argument pre-processing: mixer and flip
  8. // Acknoledgements:
  9. // - partial() is based on work by Oliver Steele
  10. // (http://osteele.com/sources/javascript/functional/functional.js)
  11. // which was published under MIT License
  12. // Defined methods:
  13. // - take any valid lambda argument as the functional argument
  14. (function(){
  15. var df = dojox.lang.functional, ap = Array.prototype;
  16. var currying = function(/*Object*/ info){
  17. return function(){ // Function
  18. var args = info.args.concat(ap.slice.call(arguments, 0));
  19. if(arguments.length + info.args.length < info.arity){
  20. return currying({func: info.func, arity: info.arity, args: args});
  21. }
  22. return info.func.apply(this, args);
  23. };
  24. };
  25. dojo.mixin(df, {
  26. // currying and partial functions
  27. curry: function(/*Function|String|Array*/ f, /*Number?*/ arity){
  28. // summary: curries a function until the arity is satisfied, at
  29. // which point it returns the calculated value.
  30. f = df.lambda(f);
  31. arity = typeof arity == "number" ? arity : f.length;
  32. return currying({func: f, arity: arity, args: []}); // Function
  33. },
  34. arg: {}, // marker for missing arguments
  35. partial: function(/*Function|String|Array*/ f){
  36. // summary: creates a function where some arguments are bound, and
  37. // some arguments (marked as dojox.lang.functional.arg) are will be
  38. // accepted by the final function in the order they are encountered.
  39. // description: This method is used to produce partially bound
  40. // functions. If you want to change the order of arguments, use
  41. // dojox.lang.functional.mixer() or dojox.lang.functional.flip().
  42. var a = arguments, l = a.length, args = new Array(l - 1), p = [], i = 1, t;
  43. f = df.lambda(f);
  44. for(; i < l; ++i){
  45. t = a[i];
  46. args[i - 1] = t;
  47. if(t === df.arg){
  48. p.push(i - 1);
  49. }
  50. }
  51. return function(){ // Function
  52. var t = ap.slice.call(args, 0), // clone the array
  53. i = 0, l = p.length;
  54. for(; i < l; ++i){
  55. t[p[i]] = arguments[i];
  56. }
  57. return f.apply(this, t);
  58. };
  59. },
  60. // argument pre-processing
  61. mixer: function(/*Function|String|Array*/ f, /*Array*/ mix){
  62. // summary: changes the order of arguments using an array of
  63. // numbers mix --- i-th argument comes from mix[i]-th place
  64. // of supplied arguments.
  65. f = df.lambda(f);
  66. return function(){ // Function
  67. var t = new Array(mix.length), i = 0, l = mix.length;
  68. for(; i < l; ++i){
  69. t[i] = arguments[mix[i]];
  70. }
  71. return f.apply(this, t);
  72. };
  73. },
  74. flip: function(/*Function|String|Array*/ f){
  75. // summary: changes the order of arguments by reversing their
  76. // order.
  77. f = df.lambda(f);
  78. return function(){ // Function
  79. // reverse arguments
  80. var a = arguments, l = a.length - 1, t = new Array(l + 1), i = 0;
  81. for(; i <= l; ++i){
  82. t[l - i] = a[i];
  83. }
  84. return f.apply(this, t);
  85. };
  86. }
  87. });
  88. })();
  89. });