这几乎是纯粹的学术变体,但是您可以为此使用修改的定点组合器。
让我们缩短并改善您的原始功能:
function singleDigit(n) {
let digitProduct = [...(n + '')].reduce((x, y) => x * y, 1);
return digitProduct <= 9 ? digitProduct : singleDigit(digitProduct);
}
// singleDigit(123234234) == 0
从这个变体中,我们可以排除并处理递归调用:
function singleDigitF(recur) {
return function (n) {
let digitProduct = [...(n + '')].reduce((x, y) => x * y, 1);
return digitProduct <= 9 ? digitProduct : recur()(digitProduct);
};
}
现在,该功能可以与定点组合器一起使用。具体来说,我实现了一个适用于(严格)JavaScript的Y组合器,如下所示:
function Ynormal(f, ...args) {
let Y = (g) => g(() => Y(g));
return Y(f)(...args);
}
我们在哪里Ynormal(singleDigitF, 123234234) == 0。
现在就来了。由于我们已经考虑了到Y组合器的递归,因此我们可以计算其中的递归数量:
function Ycount(f, ...args) {
let count = 1;
let Y = (g) => g(() => {count += 1; return Y(g);});
return [Y(f)(...args), count];
}
快速检查Node REPL会发现:
> 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 ]
现在,此组合器将用于计算以样式编写的任何递归函数中的调用次数singleDigitF。
(请注意,有越来越零是一个非常常见的回答有两个来源:数字溢出(123345456999999999成为123345457000000000等),以及当输入的大小增加时,几乎肯定会在某个地方得到零作为中间值的事实。)
.map(Number)这是多余的,因为*操作员无论如何都将值强制为数字。;-)