-2

I'm looking for a javascript function that can:

Condition (I)

compose another function when it does not have recursion in its definition, kind of like in maths when the function is given a power, but with multiple arguments possible in the first input - e.g. with a (math) function f:


f(x) := x+2

f5(x) = f(f(f(f(f(x))))) = x+10

Condition (II)

Or maybe even input custom arguments into each step of composition:


(52)2)2=

Math.pow(Math.pow(Math.pow(5,2),2),2) = Math.pow.pow([5,2],2,["r",2]])
//first arg set, how times the next, 2nd arg set - "r" stands for recursion - 
//that argument will be occupied by the same function

//Using new solution: 
_.supercompose(Math.pow,[[5,2],[_,2],[_,2]]) //-> 390625

2((52)3)=

Math.pow(2,Math.pow(Math.pow(5,2),3)) = Math.pow.pow([5,2],["r",2],["r",3],[2,"r"])

//Using new solution:
_.supercompose(Math.pow,[[5,2],[_,2],[_,3]]) //-> 244140625
_.supercompose(Math.pow,[[5,2],[_,2],[_,3],[2,_]]) //-> Infinity (bigger than the max. number)

Note: The above are just templates, the resulting function doesn't have to have the exact arguments, but the more close to this (or creative, for example, a possibility of branching off like this ->[2,4,"r",4,2,"r"], which would also be complicated) the better.

I've been attempting to do at least (I) with Function.prototype, I came up with this:

Object.defineProperty(Function.prototype,"pow",{writable:true}); 
//Just so the function not enumerable using a for-in loop (my habit)
function forceSlice(context,argsArr)
{returnArray.prototype.slice.apply(context,argsArr)}
Function.prototype.pow = function(power)
{
  var args=power<2?forceSlice(arguments,[1]):
  [this.pow.apply(this,[power-1].concat(forceSlice(arguments,[1])))];
  return this.apply(0,args);
}
//Usage:
function square(a){return a*a;}
square.pow(4,2) //65536
function addThree(a,b){return a+(b||3); } 
// gives a+b when b exists and isn't 0, else gives a+3
addThree.pow(3,5,4) //15 (((5+4)+3)+3)

Worst case, I might just go with eval, which I haven't figured out yet too. :/

Edit: Underscore.js, when played around with a bit, can fulfill both conditions. I came up with this, which is close to done, but I can't get it to work:

_.partialApply = function(func,argList){_.partial.apply(_,[func].concat(argList))}

_.supercompose = function(func,instructions)
{
_.reduce(_.rest(instructions),function(memo,value)
{
return _.partialApply(_.partialApply(func, value),memo)();

},_.first(instructions))
}
//Usage:
_.supercompose(Math.pow,[[3,2],[_,2]]) //should be 81, instead throws "undefined is not a function"

Edit: jluckin's cleareance of terms (recursion-> function composition) Edit: made example function return number instead of array

Cœur
  • 37,241
  • 25
  • 195
  • 267
Sophiα2329
  • 1,601
  • 1
  • 13
  • 15

2 Answers2

0

The term you are looking for is called function composition, not necessarily recursion. You can apply function composition in javascript easily since you can pass a function as an argument.

I created a small function called compose, which takes a function, an initial value, and the number of times to compose the function.

function compose(myFunction, initialValue, numberOfCompositions) {
    if (numberOfCompositions === 1) {
        return myFunction(initialValue);
    }
    else {
        return compose(myFunction, myFunction(initialValue), --numberOfCompositions);
    }
}

When this function is evaluated, you pass in some function f(x), some initial x0, and the repeat count. For example, numberOfCompositions = 3 gives f(f(f(x)));

If there is one composition, then f(x) is returned. If there are two compositions, compose returns f(x) with f(x) replacing x as the argument, with 1 passed in as the composition so it will evaluate f(f(x)).

This pattern holds for any number of compositions.

Since functions are treated as objects and can be passed as arguments of functions, this method basically wraps your "non-recursive" functions as recursive functions to allow composition.

jluckin
  • 662
  • 4
  • 6
  • Thanks for information on the right terminology, but I already have figured out a function that fulfills condition (I). I mentioned it in the question. I will continue trying to make a function fulfilling both conditions. – Sophiα2329 Aug 05 '14 at 18:13
0

Success(simplicity wins):

_.supercompose = function (func,instructions,context)
{
var val;
for(var i = 0; i < instructions.length; i++)
  {
 val = _.partial.apply(_,[func].concat(instructions[i])).apply(context||this,val?[val]:[]);
  }
return val;
}

//Usage (with a function constructor for operations):
_.op = function(o){return Function.apply(this,"abcdefghijklmnopqrstuvwxyz".split("").concat(["return " + o]))}
_.op("a+b")(3,5) //-> 8
_.op("a*b")(3,5) //-> 15
_.supercompose(_.op("(a+b)*c*(d||1)"),[[1,2,3],[-5,_,1],[1,2,_,3]])
//-> (1+2)*((-5+((1+2)*3))*1)*3 -> 36
Sophiα2329
  • 1,601
  • 1
  • 13
  • 15