curry.js 3.4 KB

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