Javascript 纯函数:Does";“无副作用”;暗示;总是相同的输出,给定相同的输入;?

Javascript 纯函数:Does";“无副作用”;暗示;总是相同的输出,给定相同的输入;?,javascript,functional-programming,language-lawyer,pure-function,Javascript,Functional Programming,Language Lawyer,Pure Function,将函数定义为pure的两个条件如下: 无副作用(即仅允许更改局部范围) 对于相同的输入,始终返回相同的输出 如果第一个条件始终为真,是否有第二个条件不为真的情况 也就是说,它真的只有在第一个条件下才有必要吗?这里有几个反例,它们不会改变外部范围,但仍然被认为是不纯净的: 函数a(){返回日期.现在();} 函数b(){return window.globalMutableVar;} function c(){return document.getElementById(“myInput”).v

将函数定义为
pure
的两个条件如下:

  • 无副作用(即仅允许更改局部范围)
  • 对于相同的输入,始终返回相同的输出
  • 如果第一个条件始终为真,是否有第二个条件不为真的情况


    也就是说,它真的只有在第一个条件下才有必要吗?

    这里有几个反例,它们不会改变外部范围,但仍然被认为是不纯净的:

    • 函数a(){返回日期.现在();}
    • 函数b(){return window.globalMutableVar;}
    • function c(){return document.getElementById(“myInput”).value;}
    • 函数d(){return Math.random();}
      (它确实改变了PRNG,但不被认为是可见的)
    访问非常量非局部变量足以违反第二个条件

    我总是认为纯度的两个条件是互补的:

    • 结果评估不得对侧面状态产生影响
    • 评估结果不得受到侧面状态的影响

    术语仅指第一个,即修改非局部状态的函数。然而,有时读取操作也被视为副作用:当它们是操作并且也涉及写入时,即使它们的主要目的是访问值。例如,生成修改发生器内部状态的伪随机数、从推进读取位置的输入流读取数据,或从涉及“测量”命令的外部传感器读取数据。

    可能存在来自系统外部的随机性源。假设你计算的部分包括室温。然后,根据室温的随机外部元素,每次执行该函数将产生不同的结果。执行程序不会改变状态


    无论如何,我所能想到的就是。

    在我看来,您描述的第二个条件比第一个条件的约束要弱

    让我举一个例子,假设您有一个函数添加一个也记录到控制台的函数:

    function addOneAndLog(x) {
      console.log(x);
      return x + 1;
    }
    
    满足您提供的第二个条件:当给定相同的输入时,此函数始终返回相同的输出。但是,它不是一个纯粹的函数,因为它包含登录到控制台的副作用

    严格地说,纯函数是满足函数性质的函数。这就是我们可以用函数应用程序生成的值替换它的属性,而不改变程序的行为

    假设我们有一个函数,它只添加:

    function addOne(x) {
      return x + 1;
    }
    
    我们可以在程序中的任何地方用
    6
    替换
    addOne(5)
    ,不会有任何变化

    相比之下,我们不能在程序中的任何地方用
    6
    值替换
    addOneAndLog(x)
    ,而不改变行为,因为第一个表达式会导致某些内容写入控制台,而第二个表达式则不会

    我们考虑任何额外的行为:<代码> AdOnand日志(x)除了将输出作为“强”>副作用< /强> .< /P> < P> >“正常”的措辞,纯函数是指引用透明度。如果函数是引用透明的,那么它就是纯函数

    粗略地说,引用透明性意味着您可以在程序中的任何一点将对函数的调用替换为其返回值,反之亦然,而无需更改程序的含义

    因此,例如,如果C的
    printf
    是引用透明的,那么这两个程序应该具有相同的含义:

    printf("Hello");
    
    5 + 5;
    
    printf("Hello") + 5;
    
    printf("Hello") + printf("Hello");
    

    以下所有程序应具有相同的含义:

    printf("Hello");
    
    5 + 5;
    
    printf("Hello") + 5;
    
    printf("Hello") + printf("Hello");
    
    因为
    printf
    返回写入的字符数,在本例中为5

    使用
    void
    函数时,这种情况更加明显。如果我有一个函数
    void foo
    ,那么

    foo(bar, baz, quux);
    
    应与相同

    ;
    
    也就是说,由于
    foo
    不返回任何内容,我应该能够在不改变程序含义的情况下将其替换为“无”

    显然,
    printf
    foo
    都不是引用透明的,因此它们都不是纯的。事实上,
    void
    函数永远不能是引用透明的,除非它是no-op

    我发现这个定义和你给出的定义一样容易处理。它还允许您在任何粒度上应用它:您可以将它应用于单个表达式、函数和整个程序。例如,它允许您讨论如下函数:

    func fib(n):
        return memo[n] if memo.has_key?(n)
        return 1 if n <= 1
        return memo[n] = fib(n-1) + fib(n-2)
    
    func fib(n):
    返回备忘[n]如果备忘有_键?(n)
    如果n,则返回1
    如果第一个条件始终为真,第二个条件是否存在
    情况不是真的吗

    考虑下面的简单代码片段

    public int Sum(int a, int b) {
        Random rnd = new Random();
        return rnd.Next(1, 10);
    }
    
    该代码将返回相同给定输入集的随机输出-但是它没有任何副作用


    您提到的两点#1和#2组合在一起时的总体效果意味着:在任何时间点,如果在程序中使用相同i/p的函数
    和替换为其结果,则程序的总体含义不会改变。这只不过是。

    FP定义的问题在于它们非常人为。每次评估/计算都会对评估者产生副作用。理论上是正确的。对此的否认只表明FP辩护者忽视了哲学和逻辑:“评估”意味着改变某些智能环境(机器、大脑等)的状态。这是评估过程的本质。没有变化-没有“结石”。效果可以非常明显:加热CPU或i