1

我试图在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)之间的区别是什么,这样一个工程和其他崩溃。

+1

因为严格评估。 – Bergi

+1

@Bergi三个字 - 我把它称为一个懒惰的解释:D – ftor

回答

2

我认为正在发生的是那两个表达式不完全相同。

一方面x => f(f)(x) - 这将创建一个新的函数文本(所以它不会被调用的时候了 - 它被调用,只有当这个函数被调用)

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

+1

或换句话说,'x => f(f)(x)'是f(f)'的懒惰版本。由于Javascript是严格评估的,我们必须将'f(f)'这样的模式包装到lambda中以避免无限递归。 – ftor

+0

我认为这是问题的关键。表达式x => f(f)(x)延迟f(f)的评估直到提供x。 –

4

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()

相关问题