/**
 *	Extends JavaScript Functions to allow currying s.t. f(a, b) == f(a)(b)
 *	@author Chris Bouchard
 *	@date 2008-01-28
 */

Function.prototype.partial = function ()
{
	var partialArgs = Array.prototype.slice.call(arguments, 0);
	var func = this;
	
	var retFunc = function ()
	{
		var args = Array.prototype.slice.call(arguments, 0);
		return func.apply(this, partialArgs.concat(args));
	};

	return retFunc.toArity(Math.max(0, func.length - partialArgs.length));
};

Function.prototype.toCurriable = function ()
{
	var func = this;

	var retFunc = function ()
	{
		if (arguments.length < func.length)
		{
			return func.partial.apply(func, arguments).toCurriable();
		}

		return func.apply(this, arguments);
	};

	return retFunc.toArity(func.length);
};

Function.prototype.toArity = function (n)
{
	var func = this;
	var parmString = '';
	var funcString = '';
	var i;
	
	if (n == func.length)
	{
		return func;
	}

	if (n == 0)
	{
		return function ()
		{
			return func.apply(this, arguments);
		};
	}

	for (i = 0; i < n; ++i)
	{
		parmString += 'a' + i;

		if (i < n - 1)
		{
			parmString += ',';
		}
	}

	funcString = '(function (' + parmString + ') { return func.apply(this, arguments); })';
	return eval(funcString);
};
