函数式编程和闭包/部分应用

时间:2017-04-09 09:52:38

标签: javascript functional-programming closures

我对函数式编程的本质感到困惑。提到高阶函数是关键概念之一,它可以实现闭包和部分应用等技术,即捕获状态策略以及要返回的功能。

然而,另一个关键概念是纯函数不可变状态。换句话说,功能不会产生副作用或读取外部状态。它们应始终使用相同的参数返回相同的结果。

这似乎与高阶函数的概念相矛盾,其中函数确实可以访问由闭包封装的状态。当然,这并不意味着功能必须改变状态,但至少状态会影响它的行为。

换句话说,相同的函数可能在后续的程序执行中返回不同的结果。或者我误解了,相同的是什么意思?我想到的是一个同名和一个身体的功能,关闭与否。毕竟,我们谈论的是类似数学的函数,而不是一个独特实体的方法。我是否应该将更高阶函数返回的函数视为不同的函数,而不仅仅是参照,而是作为定义?

2 个答案:

答案 0 :(得分:3)

在后续的程序执行中,它可能不会返回不同的结果。

function adder(init) {
  return (arg) => init + arg;
}    

返回一个函数。它每次返回一个不同的函数,但是使用相同的参数返回一个与前一个函数完全相同的函数。这使得这纯洁。

const add10 = adder(10);
const add20 = adder(29);

add10add20不同的功能。它们运行相同的代码,但在不同的闭包中。它们都是纯粹的,因为它们的返回值仅取决于它们的输入。

通常很容易从代码中看到mutate的闭包,但是变异的全局变量更加困难。我曾经多次在加载库时Object已经发生变异,但并不总是这样,前后的结果是相同的。函数纯度依赖于自由变量,全局变量是最易受自由变量影响的函数。

答案 1 :(得分:1)

来自Wikipedia

  

在计算机编程中,如果关于该函数的以下两个陈述都成立,则函数可被视为纯函数:

     

在给定相同参数值的情况下,函数始终评估相同的结果值。功能结果值不能取决于程序执行过程中或程序执行不同时可能发生的任何隐藏信息或状态,也不依赖于I / O设备的任何外部输入(通常 - 见下文)。

     

评估结果不会导致任何语义上可观察到的副作用或输出,例如可变对象的突变或输出到I / O设备(通常见下文)。

因此,纯度是由函数的行为定义的,如果函数的行为是这样的,即使结果依赖于某个封装的内部状态,结果仍保持相同,那么函数将是纯粹的。

此函数纯,因为它的返回值(恰好是函数)在相同的调用中有所不同:

function x() {                   // Not Pure because return value depends on external effect.
    const x = Math.random();
    return () => x;             // Pure
}

同样:

function x() {
    let x = 0
    return {
        fn1(y) {           // Not pure 
            x = x + y      // side effect which is observable through fn2
            return x
        },
        fn2() {            // Not pure because outcome depends on external environment besides arguments
            return x       // x is exposed to outside world through fn1
        }
    }
}

因此,杂质具有传染性。将状态暴露于来自外部世界的突变的不纯函数使得任何其他函数依赖于相同的状态不纯。

相反,以下是纯粹的(假设昂贵的计算功能是纯粹的):

function x() { 
    let x;
    return () => {                         
        x = x || expensiveComputation() // side effect is not observable/exposed to outside world
        return x
    }
}

这一个也是如此:

function fn(x) {           // Pure
    return {
        next() {
          return x + 1;
       }
       prev() {
         return x - 1;
       }
   }
}

y = fn(x)
y.next() // Pure 
y.prev() // Pure