gpt4 book ai didi

没有条件的Javascript递归

转载 作者:行者123 更新时间:2023-11-30 11:15:40 25 4
gpt4 key购买 nike

我正在尝试“实现”Church's encoding of lambda calculus在 Javascript 中,但是当我编写阶乘函数时开始遇到问题:

const factorial = n => (iszero(n))(ONE)(multiply(n)(factorial(predecessor(n))));

iszero(n) 作为条件,返回一个函数,如果 n 为零则执行第一个参数,否则返回第二个参数。

对任何值调用此函数都会导致堆栈溢出。

我试图简化它以找出原因:

//const ifelse = condition => a => b => condition ? a : b;
//const factorial = n => ifelse(n == 0)(1)(n * factorial(n - 1));
const ifelse = function(condition, a, b) {
if (condition) {
return a;
} else {
return b;
}
}
const factorial = function(number) {
return ifelse(number == 0, 1, number * factorial(number - 1));
}

在这里调用 factorial 也会导致溢出,尽管如果我们减少 factorial 中的 ifelse 函数,它会生成一个不会抛出的完美函数 factorial 函数:

//const factorial = n => (n == 0) ? (1) : (n * factorial(n - 1));
const factorial = function(number) {
if (number == 0) {
return 1;
} else {
return number * factorial(number - 1);
}
}

但是我试图在阶乘中只使用函数,所以三元条件运算符是 Not Acceptable (参见注释箭头符号)。

为什么我的 factorial 函数在对任何值调用时会导致堆栈溢出,是否可以在仍然仅使用函数(无条件)的情况下避免这种情况?

编辑:第一段代码的定义:

const TRUE = x => y => x;
const FALSE = x => y => y;

const ZERO = f => x => x;
const ONE = f => x => f(x);

const pair = a => b => f => f(a)(b);

const first = p => p(TRUE);
const second = p => p(FALSE);

const iszero = n => n(x => FALSE)(TRUE);

const successor = n => f => x => f(n(f)(x));
const multiply = n1 => n2 => f => x => n1(n2(f))(x);
const predecessor = n => second(n(p => pair(successor(first(p)))(first(p)))(pair(ZERO)(ZERO)));

最佳答案

你会遇到堆栈溢出,因为 JavaScript 不是惰性求值语言。例如:

ifelse(false)(console.log("YES"))(console.log("NO"))
// => YES
// NO

两个参数都被评估。防止这种情况发生的方法是将它们保留为函数,直到您需要它们为止。

ifelse(false)(() => console.log("YES"))(() => console.log("NO"))()
// => NO

因此,在您的第二个 factorial 定义中,无论如何都会执行 factorial(n - 1)ifelse 只是让您选择要返回的两个值中的哪一个。显然,factorial(0) 随后将调用 factorial(-1),这将一直持续到 -infinity,受内存限制。

不对它们求值:

factorial = n => ifelse(n == 0)(() => 1)(() => n * factorial(n - 1)())
factorial(1)()
# => 1
factorial(5)()
// => 120

鉴于您没有定义,我无法告诉您第一组有什么问题,但原因可能是相同的。

编辑:看过定义后...让我先添加一个我自己的定义:

const display = n => n(x => x + 1)(0)

(n(x => x + 1)(0) 是一个将教堂数字转换为普通数字的便捷技巧,因此我们可以看到发生了什么。仅用于调试工具,因此它应该不要违反你所做事情的纯洁性。)

我们的检查员在手……predecessor 不正确。见:

display(successor(predecessor(ONE)))
// => TypeError: f(...) is not a function
// at f (repl:1:33)
// at x (repl:1:36)

试试这个(直接从您的维基百科链接):

const predecessor = n => f => x => n(g => h => h(g(f)))(u => x)(u => u)

有了它,您会得到正确的结果:

display(successor(predecessor(ONE)))
// => 1

现在,转向阶乘。应用与上面相同的技巧(将 ifelse 分支包装到闭包中以防止它们过早评估):

const factorial = n => (iszero(n))(() => ONE)(() => multiply(n)(factorial(predecessor(n))()));

const FIVE = successor(successor(successor(successor(ONE))));
display(factorial(FIVE)())
// => 120

关于没有条件的Javascript递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51667631/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com