在 Javascript 为什么我不能用 f(f) 替换 x => f(f)(x)?

In Javascript why can't I replace x => f(f)(x) by f(f)?

我试图在 Javascript 中实现 Y 组合器。

我设法实现了以下内容:

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)

是一个接受一个参数的函数,x。当调用该函数时,它会依次调用函数 f,将对 f 的引用作为参数传递。函数 f returns 另一个函数,然后调用它,将 x 作为参数传递。

在老式语法中,它是

function(x) {
  return f(f)(x);
}

这与 f(f) 本身有很大不同。这只是函数 "f" 的调用,其中 "f" 作为参数传递。

所以x => f(f)(x)f(f)都是表达式,但是它们代表了截然不同的语义。第一个的值是对函数的引用;表达式本身 不做任何其他事情 — 特别是,函数 f() 没有被调用。 f(f) 的值是函数 f() returns 被调用时的值——表达式 做某事,即函数 f() 做的任何事情.

我认为这两个表达式并不完全相同。

一方面 x => f(f)(x) - 这会创建一个新的函数文字(因此它不会立即被调用 - 它仅在调用此函数时被调用)

另一方面 f(f) - Javascript 中的 this 是一个调用 f 函数的表达式。所以在你的情况下会导致堆栈溢出。