Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add delay to recursive function without modifying it

Let's say function fib():

function fib(n) {
  if (n < 2){
    return n
  }
  return fib(n - 1) + fib (n - 2)
}

Now, let's say I want to display each step of this recursive function in a document.write, and progressively add the result of each iteration with a delay of 1000ms between steps. Can I do it without modifying the original function by perhaps having another function, passing this one as the argument, creating the output mechanism, and since it also returns a function, recursively add the delay?

like image 544
aabreu Avatar asked May 14 '26 03:05

aabreu


2 Answers

No, but writing it as a generator instead would give you a useful interface to implement something like that

function*fib() {
  for (let a = 1, b = 1, c = 0;; c = a+b, a = b, b = c) yield a;
}
const sleep = ms => new Promise(resolve => setTimeout(() => resolve(), ms));
const gen = fib();

// then, use it step by step

console.log(gen.next().value); 
console.log(gen.next().value); 

// OR with a delay inbetween  
 
async function slowly() {
  for (let v of gen) {
    console.log(v);
    await sleep(1000);
  }
}
slowly();
like image 63
ᅙᄉᅙ Avatar answered May 16 '26 16:05

ᅙᄉᅙ


Because your original function is synchronous, without modifying you cannot really call it as if it were asynchronous.

JavaScript allows you to overwrite a symbol like your function, fib. This allows you to redefine it whatever you just want. Maybe you could make it asynchronous with dynamically added behavior, I don't know, but that would be too complicated.

However, you said "I want to display each step of this recursive function ... with a delay of 1000 ms between steps". You can easily do this, because you can call fib synchronously, but print the results asynchronously! Example:

function fib(n) {
  if (n < 2){
    return n
  }
  return fib(n - 1) + fib (n - 2)
}

var queue = [];
var depth = 0;
var manageCall = function(fn){
    return function() {
        ++depth;
        let result = fn.apply(this, arguments);
        --depth;
        queue.push(" ".repeat(depth)+fn.name+"("+arguments[0]+") = "+result);
        return result;
    };
};
var fib = manageCall(fib);
fib(8);
var printDelayed = function() {
    if (queue.length != 0) {
        console.info(queue.pop());
        setTimeout(printDelayed, 1000);
    }
}
printDelayed();

fib is unchanged, but can follow how the recursion were executed.

like image 43
klenium Avatar answered May 16 '26 17:05

klenium