Last active
August 29, 2015 14:00
-
-
Save yiransheng/11384197 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A dirty hack to achieve true function currying in javascript | |
**/ | |
var curry = (function() { | |
/* ---> | |
* wrap everything in a private scope; | |
*/ | |
/* Generates an array of unique named variable/argument names | |
* of length k. | |
*/ | |
var identifiers="abcdefghijklmnopqrstuvwxyz"; | |
function named_args(k) { | |
var args=[],n = identifiers.length; | |
while(k--) { | |
args.push(k.toString(n).split("").map(function(x) { | |
return identifiers.charAt(parseInt(x, n)) | |
}).join("")) | |
} | |
return args | |
} | |
/* It takes a function f(x) which returns another function g(y) as a result, | |
* and yields a new function f′(x,y) which takes a number of additional | |
* parameters and applies them to the function returned by function f. | |
* The process can be iterated if necessary. | |
*/ | |
function uncurry(fn) { | |
return function() { | |
var i, f, len = arguments.length; | |
f = fn; | |
for(i=0;i<len;i++) { | |
f = f(arguments[i]) | |
} | |
return f; | |
} | |
} | |
/* Transforming a function that takes multiple arguments in such a way | |
* that it becomes a chain of functions, [f(x,y,z) => g(x)(y)(z)] | |
* each with a single argument, then uncurry the output function, | |
* so that it can be used with more flexibility, taking any number (less | |
* than the length of the chain of functions), and return the remainder of | |
* the chain. | |
*/ | |
function curry(fn) { | |
var len = fn.length, | |
args = named_args(len), | |
body = 'return fn('+args.join(',')+')', | |
arg, | |
f; | |
// only works on functions with more than one named (of known number) arguments | |
if (len < 2) return fn; | |
// has to use eval for function def, as the "Function" constructor | |
// does not create a nice closure, which we need so that the returned | |
// function chain has access to the original function | |
// see: http://www.bennadel.com/blog/1909-javascript-function-constructor-does-not-create-a-closure.htm | |
eval('f=function ('+args.pop()+'){'+ body + '}'); | |
while(arg=args.pop()) { | |
eval('f=function ('+arg+'){return uncurry('+f.toString()+ ')}') | |
} | |
return uncurry(f) | |
} | |
return curry; | |
//<--- | |
})(); | |
// basic examples | |
var sum6 = function(x,y,z,u,v,w) { | |
return x+y+z+u+v+w; | |
}; | |
var sum6_ = curry(sum6); | |
sum6_(1)(1)(1)(1)(1)(1) === 6; // true | |
sum6_(1,1,1,1,1,1) === 6 // true | |
sum6_(1,1,1)(1,1,1) === 6 //true | |
var sum5_ = sum6_(2), | |
sum4_ = sum6_(2,3); | |
sum4__ = sum6_(2)(3); // they are all functions | |
sum5_(1,1,1,1,1) === 7; // true | |
sum4_(1,1,1,1) === 9; // true | |
sum4__(1)(1)(1,1) === 9; //true | |
// more "useful" examples | |
var _reduce = curry(function (fn, memo, arry) { | |
return arry.reduce(fn, memo) | |
}); | |
var sum = _reduce(function(s, x){ return s+x }, 0); | |
var product = _reduce(function(p, x){ return p*x })(1); | |
sum([1,2,3,4]) === 10 // true | |
product([1,2,3,4]) === 24 // true | |
// | |
var each = curry(function(fn, arry) { | |
return arry.forEach(fn); | |
}); | |
var attachElement = curry(function(tagName, parentNode, className, id, html) { | |
var e = document.createElement(tagName); | |
e.id = id; | |
e.className = className; | |
e.innerHTML = html; | |
parentNode.appendChild(e); | |
return e; | |
}); | |
var createDiv = attachElement('DIV', document.body); | |
var createColorfulDivs = each(function(d) { | |
createDiv(d.cls, d.id, d.content); | |
}); | |
var data=[{ id:1, content: "I am red.", cls: "red"}, | |
{ id:2, content: "I am blue.", cls: "blue"}, | |
{ id:3, content: "I am yellow.", cls: "yellow"}, | |
{ id:4, content: "I am black.", cls: "black"}]; | |
createColorfulDivs(data); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment