How to effectively determine valve depth

In terms of closure, only account is used for functions returning another function, as shown in the following examples. How do we programmatically determine the depth of this closure at runtime?

Let's say this function F

has a depth of 2:

function F(a){ // 1
    return function G(b){ // 2
        return 'something';
    }
}

      

This "H" function has a depth of 3.

function H(a){ // 1
   return function(b){ //2
      return function(c){} //3
   }
}

      

So far I've made some simple script to determine the depth of the closure, iteratively check the return type of the function until it returns a type other than a function. But my script only works when no argument is needed for each nested function . See the following code:

function F(){
    return function(){
        return function(){
            return 1;
        }
   }
}

function depth(f){
    var n = 1;
    var ret = f();
    while (typeof(ret)=='function'){
        ret = ret(); 
        n++;
    }
    return n; 
}

      

The simple function depth

above correctly determines the depth F

, which is 3. However, in some real world cases, such as closures, which take a function as an argument and call it, my function depth

cannot deal.

function F2(a,f){
    return function(g){
        return f(a) + g(a); // This will break my depth function
   }
}

      

* My question is : Is there a way to determine how deep my closure is more efficient? Especially in some of the cases mentioned above (closures that take a function as an argument and call it). A general approach that can dynamically deal with closures, which may or may not take some functions as arguments, will be most appreciated.

PS Let me narrow the scope as follows.

  • Only purely nested functions are counted.
  • Each layer of a nested function always returns the same type.
  • The depth of the function is constant.
  • None of the nested functions are recursive.
+3


source to share


3 answers


Here's another approach. This works at runtime by observing how the code works.
My function Reflector

is a special sauce in this case.
See https://jsfiddle.net/rffv34oz/8/ to run the example.

The function Reflector

has four functions:
1. It "executes" the function with a hook ( fh

), returning the hook instead of the original function. The effect is that the hook is called before the tool function is called.
2. When a tool function is called, it forwards the call — it calls the original function. And it remains ready to capture the result of the function.
3. When the function returns, it checks the result. If the result is also a function, it retains the new maximum depth.
4. In addition, when the return value was a function, the hook also displays the returned function, so step (1) is applied again for the new returned function.



//Your function You want to USE and REFLECT on too.
function F(){ 
    //return 3;
    return function(){
        //return 2;
        return function(){
            return 1;
        }
   }
}

//Your function You want to USE and REFLECT on too.
function H(a){ // 1
    return function(b){ //2
        return function(c){ //3
            return a + b + c;   
        }
   }    
}

//this function is the machinery that knows how to USE the functions You want to measure. 
//But this function only USES them, but does no reflection.
function BlackboxF(f) { 

    var r1 = f();
    if (typeof r1 == "function")
    {
        var r2 = r1();
        if (typeof r2 == "function")
        {
            var r3 = r2();  

            return r3;
        }
        else 
        {
            return r2;   
        }
    }
    else 
    {
         return r1;   
    }

}

//this function is the machinery that knows how to USE the functions You want to measure. 
//But this function only USES them, but does no reflection.
function BlackboxH(f) { 

    var r1 = f(1);
    var r2 = r1(2);
    var r3 = r2(4);
    return r3;

}

var maxdepth = 1;

//This is the special agent for reflecting code as it runs
function Reflector(f, depth) { 

    if (!depth)
        depth = 1;

    //1. It "instruments" a function with a hook (`fh`) by returning the hook 
    //instead of the original function. The effect is that the hook is called 
    //before that instrumented function is called.
    var fh = function()     
    {
        //2. When the instrumented function is called, it forwards the call - it calls 
        //the original function. And remains ready for capturing the function result.
        var r = f.apply(this, arguments);    

        //3. When the function returns, it inspects the result. 
        //If the result is also a function, it stores new maximum depth.
        if (typeof r == "function")
        {
            maxdepth = Math.max(maxdepth, depth + 1);

            //4. Also, when the returned result was a function, the hook also 
            //instruments the returned function, so that step (1) is again applied 
            //for the new returned function.
            return Reflector(r, depth + 1);        
        }
        else 
        {
            return r;
        }
    };

    return fh;
}

if (false) //The simple case with no arguments
{
    var F2 = Reflector(F);
    var RF = BlackboxF(F2);

    document.getElementById("result").textContent = "Result: " + RF;
    document.getElementById("depth").textContent = "Depth: " + maxdepth;
}
else //A more complicated case with arguments
{
    var H2 = Reflector(H);
    var RH = BlackboxH(H2);

    document.getElementById("result").textContent = "Result: " + RH;
    document.getElementById("depth").textContent = "Depth: " + maxdepth;
}

      

+1


source


This is more of a comment than an answer, but it's better to format it here.

This is not a solvable problem unless you provide a set of all the required parameters.
Calculate the "depth" of the following:



function F(a) {
    if (a) {
        return function G(b) {
            return 0;
        }
    } else {
        return 1;
    }
}

      

+1


source


Perhaps you can change all the functions so that they can work without arguments, for your purpose?
Because during depth computation, function calls should not do any other useful computation or have any side effects. They should simply return a function or non-functional value.
Because you say, “Each layer of a nested function always returns the same type. The depth of the function is constant.” The decision to return a dummy response of the appropriate type when faced with an empty argument list should be simple.

+1


source







All Articles