在Javascript中,为什么我不能用f(f)代替x => f(f)(x)?
我试图在Javascript中实现Y组合器。在Javascript中,为什么我不能用f(f)代替x => f(f)(x)?
我设法执行下列规定:
const y0 = gen => (f => f(f))(f => gen(x => f(f)(x)));
const factorial0 = y0(fact => n => n<=2 ? n : n * fact(n-1));
console.log(factorial0(5));
// 120
它运作良好。
然后我正在考虑表达式x => f(f)(x)
。
我的理解是,表达式x => g(x)
等于g
。将y
应用于x => g(x)
评估为g(y)
,同时将y
应用于g
也评估为g(y)
。
所以我用f(f)
替换了x => f(f)(x)
。
const y = gen => (f => f(f))(f => gen(f(f)));
const factorial = y(fact => n => n<=2 ? n : n * fact(n-1));
console.log(factorial(5));
// RangeError: Maximum call stack size exceeded
但是这个版本崩溃了堆栈溢出。
那么x => f(f)(x)
和f(f)
之间的区别是什么,这样一个工程和其他崩溃。
我认为正在发生的是那两个表达式不完全相同。
一方面x => f(f)(x)
- 这将创建一个新的函数文本(所以它不会被调用的时候了 - 它被调用,只有当这个函数被调用)
在另一方面f(f)
- 这在Javascript中是一个表达式调用f
函数。所以你的情况会导致堆栈溢出。
或换句话说,'x => f(f)(x)'是f(f)'的懒惰版本。由于Javascript是严格评估的,我们必须将'f(f)'这样的模式包装到lambda中以避免无限递归。 – ftor
我认为这是问题的关键。表达式x => f(f)(x)延迟f(f)的评估直到提供x。 –
好
x => f(f)(x)
是采取一个参数,x
功能。当函数被调用时,它又调用函数f
,将参考传递给f
作为参数。函数f
返回另一个函数,然后调用该函数,并将x
作为参数传递。
在老派的语法,这是
function(x) {
return f(f)(x);
}
这不仅仅是f(f)
本身显著不同。这只是函数“f”的调用,而“f”作为参数传递。
因此x => f(f)(x)
和f(f)
都是表达式,但它们表示明显不同的语义。第一个值是对函数的引用;表达式本身不做其他任何事情 —特别是,不调用函数f()
。 f(f)
的值是什么函数f()
当被调用时返回—表达式确实是做些什么,那是什么函数f()
。
因为严格评估。 – Bergi
@Bergi三个字 - 我把它称为一个懒惰的解释:D – ftor