Keep track of how many times a recursive function was called

后端 未结 9 1960
醉梦人生
醉梦人生 2021-02-02 05:03



        
9条回答
  •  失恋的感觉
    2021-02-02 05:57

    This is an almost purely academic variant, but you can use a modified fixed point combinator for this purpose.

    Lets shorten and improve your original function a bit:

    function singleDigit(n) {
        let digitProduct = [...(n + '')].reduce((x, y) => x * y, 1);
        return digitProduct <= 9 ? digitProduct : singleDigit(digitProduct);
    }
    
    // singleDigit(123234234) == 0
    

    From this variant, we can factor out and curry the recursive call:

    function singleDigitF(recur) {
        return function (n) {
            let digitProduct = [...(n + '')].reduce((x, y) => x * y, 1);
            return digitProduct <= 9 ? digitProduct : recur()(digitProduct);
        };
    }
    

    This function can now be used with a fixed point combinator; specifically I implemented a Y combinator adapted for (strict) JavaScript as follows:

    function Ynormal(f, ...args) {
        let Y = (g) => g(() => Y(g));
        return Y(f)(...args);
    }
    

    where we have Ynormal(singleDigitF, 123234234) == 0.

    Now comes the trick. Since we have factored out the recursion to the Y combinator, we can count the number of recursions within it:

    function Ycount(f, ...args) {
        let count = 1;
        let Y = (g) => g(() => {count += 1; return Y(g);});
        return [Y(f)(...args), count];
    }
    

    A quick check in the Node REPL gives:

    > Ycount(singleDigitF, 123234234)
    [ 0, 3 ]
    > let digitProduct = (n) => [...(n + '')].reduce((x, y) => x * y, 1)
    undefined
    > digitProduct(123234234)
    3456
    > digitProduct(3456)
    360
    > digitProduct(360)
    0
    > Ycount(singleDigitF, 39)
    [ 4, 3 ]
    

    This combinator will now work for counting the number of calls in any recursive function written in the style of singleDigitF.

    (Note that there's two sources of getting zero as a very frequent answer: numeric overflow (123345456999999999 becoming 123345457000000000 etc.), and the fact that you will almost surely get zero as an intermediate value somewhere, when the size of the input is growing.)

提交回复
热议问题