【问题标题】:In Javascript why can't I replace x => f(f)(x) by f(f)?在 Javascript 中,为什么我不能用 f(f) 替换 x => f(f)(x)?
【发布时间】:2017-02-25 15:39:28
【问题描述】:

我试图在 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 =&gt; f(f)(x)

我的理解是表达式x =&gt; g(x)等价于g。将任何y 应用于x =&gt; g(x) 计算结果为g(y),而将y 应用于g 也计算结果为g(y)

所以我将x =&gt; f(f)(x) 替换为f(f)

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 =&gt; f(f)(x)f(f) 有什么区别,一个工作,另一个崩溃。

【问题讨论】:

  • 因为严格的评价。
  • @Bergi 三个字——我称之为懒惰的解释:D

标签: javascript lambda functional-programming lazy-evaluation evaluation


【解决方案1】:

x => f(f)(x)

是一个带有一个参数的函数,x。当函数被调用时,它依次调用函数f,将f 的引用作为参数传递。函数f 返回另一个函数,然后调用它,x 作为参数传递。

在老式语法中,它是

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

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

所以x =&gt; f(f)(x)f(f) 都是表达式,但它们代表的语义明显不同。第一个的值是对函数的引用;表达式本身不做任何其他事情——特别是,函数f() 没有被调用。 f(f) 的值是 f() 在调用时返回的任何函数 — 表达式 确实 做某事,也就是 f() 所做的任何函数。

【讨论】:

    【解决方案2】:

    我认为正在发生的事情是这两种表达方式并不完全相同。

    一方面x =&gt; f(f)(x) - 这会创建一个新的函数字面量(因此不会立即调用它 - 只有在调用此函数时才会调用它)

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

    【讨论】:

    • 或者换句话说,x =&gt; f(f)(x)f(f) 的惰性版本。由于 Javascript 是经过严格评估的,我们必须将 f(f) 之类的模式包装到 lambda 中以避免无限递归。
    • 我认为这是问题的症结所在。表达式 x=>f(f)(x) 延迟 f(f) 的计算,直到提供 x。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多