4

Let's say I have a function called f that takes an integer argument called x and returns an integer. I also have an integer n that says how many times the function must call itself. So for example if my function call looks like this f(x) when n = 1, then it would look like this f(f(f(x))) when n = 3. How could something like that look in my example bellow:

function succ(n) {
  return function (f, x) {
    return f(x);
  };
}
qwerfd
  • 97
  • 8

4 Answers4

5

You could loop inside the inner function:

 for(let i = 0; i < n; i++) x = f(x);
 return x;

or alternatively let your function call itself:

 return n > 0 ? succ(n - 1)(f, f(x)) : x;
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
0

We can express this algorithm corecursively. Corecursion builds its result on the way forward from the starting point:

const iterate = f => x =>
  [x, () => iterate(f) (f(x))];

const main = iterate(x => x * 2) (1);

console.log(
  main[1] () [1] () [1] () [1] () [1] () [1] () [1] () [1] () [0]); // 256

This is just a proof of concept but not what we actually want. How can we avoid the clunky interface? We can use a Proxy to make the non-argument function implicit. It is basically the same mechanism as with lazy property getters. Additionally we don't want to access values from the stream manually but with a function for convenience:

class ThunkProxy {
  constructor(f) {
    this.memo = undefined;
  }

  get(g, k) {
    if (this.memo === undefined)
      this.memo = g();

    if (k === THUNK)
      return true;

    else if (k === Symbol.toPrimitive)
      return () => this.memo;

    else if (k === "valueOf")
      return () => this.memo;

    else return this.memo[k];
  }
}

const THUNK = "thunk";

const thunk = f =>
  new Proxy(f, new ThunkProxy(f));

const iterate = f => x =>
  [x, thunk(() => iterate(f) (f(x)))];

const takeNth = n => ([head, tail]) =>
  n === 0
    ? head
    : takeNth(n - 1) (tail);
    
const main = iterate(x => x * 2) (1);

console.log(
  main[1] [1] [1] [1] [1] [1] [1] [1] [0]); // 256

console.log(
  takeNth(16) (main)); // 65536
0

You could build a times high order function and use it to wrap other functions...

const times = (fn, n) => (...args) => {
  if (!n) { return; }
  
  fn(...args);
  
  return times(fn, n - 1)(...args);
}

const log10 = times(console.log, 10);

log10('hello');
Hitmands
  • 13,491
  • 4
  • 34
  • 69
0

Or with ES6 and recursively:

function (el, calls) {
  return calls > 1 ? getChild(el.children[0], calls - 1) : el.children[0];
}
leonheess
  • 16,068
  • 14
  • 77
  • 112