Functional programming 这是一个引用透明的函数吗?

Functional programming 这是一个引用透明的函数吗?,functional-programming,Functional Programming,下面的add函数是否是引用透明的 const appState = { runningTotal: 0 } function add(x, y) { const total = x + y; appState.runningTotal += total; return total; } 我不确定答案,因为我发现了一些关于引用透明度的定义。以下是我对其正确性的信心 如果满足以下条件,则函数是引用透明的: 它可以被它的值替换,并且程序的行为保持不变 给定一些输入,

下面的add函数是否是引用透明的

const appState = {
    runningTotal: 0
}

function add(x, y) {
    const total = x + y;
    appState.runningTotal += total;
    return total;
}
我不确定答案,因为我发现了一些关于引用透明度的定义。以下是我对其正确性的信心

如果满足以下条件,则函数是引用透明的:

它可以被它的值替换,并且程序的行为保持不变 给定一些输入,它将始终产生相同的输出 它只取决于它的输入 它是无国籍的 鉴于上述每种定义,我认为答案是:

也许-我认为这取决于appState.runningTotal在程序中其他地方的使用方式,但我不确定。 对 我不确定-它只依赖于它的输入来产生输出,但它也在函数体中使用appState 不 回到具体问题:add引用是否透明

const appState = {
    runningTotal: 0
}

function add(x, y) {
    const total = x + y;
    appState.runningTotal += total;
    return total;
}
提前谢谢


请告诉我是否合并了多个概念,即纯函数的概念。

纯函数是引用透明的。我把它称为copypastability,也就是你可以复制粘贴引用透明代码的每一部分,它仍然可以像最初预期的那样工作

这四个标准都必须满足,尽管您可以将它们缩减到第一个语句。其他的都可以从这一点推断出来


如果一个函数可以被合理地替换,这意味着您可以用一个映射/字典来替换它,该映射/字典将输入作为键,输出作为值。所以它总是在相同的输入上返回相同的内容。同样的类比也适用于只依赖于输入和无状态的函数。

纯函数是引用透明的。我把它称为copypastability,也就是你可以复制粘贴引用透明代码的每一部分,它仍然可以像最初预期的那样工作

这四个标准都必须满足,尽管您可以将它们缩减到第一个语句。其他的都可以从这一点推断出来


如果一个函数可以被合理地替换,这意味着您可以用一个映射/字典来替换它,该映射/字典将输入作为键,输出作为值。所以它总是在相同的输入上返回相同的内容。同样的类比也适用于只依赖于输入和无状态的函数。

不,它不是一个引用透明的函数

引用透明性具体指的是您列出的第一个标准,即您可以自由替换表达式左侧和右侧的值,而无需更改程序的行为


add2,3返回值5,但不能在程序中用5替换add2,3的实例,因为add2,3还有将runningTotal增加5的副作用。用add2,3代替5将导致runningTotal不增加,从而改变程序的行为。

不,它不是一个引用透明的函数

引用透明性具体指的是您列出的第一个标准,即您可以自由替换表达式左侧和右侧的值,而无需更改程序的行为

add2,3返回值5,但不能在程序中用5替换add2,3的实例,因为add2,3还有将runningTotal增加5的副作用。用add2,3代替5将导致runningTotal不增加,从而改变程序的行为。

我同意

可能-这取决于appState.runningTotal的使用方式

如果不使用,则可以忽略它。显然,它是全局状态,但它只是为了调试,还是实际应用程序状态的一部分?如果是后者,那么函数当然不是纯粹的-它确实会改变状态,用结果值替换调用,或者执行结果被丢弃的不必要调用会改变程序的行为

但是如果你考虑AppStut.RunnEnter不是你程序的语义的一部分,并且它的功能不依赖于它,那么你不妨忽略这个副作用。我们总是这样做,每一个真实世界的计算都影响它运行的计算机的状态,当我们考虑函数的纯度时,我们会选择忽略它。 可能-这取决于appState.runningTotal的使用方式

如果不使用,则可以忽略它。显然,它是全局状态,但它只是为了调试,还是实际应用程序状态的一部分?如果是后者,那么函数当然不是纯粹的-它确实会改变状态,用结果值替换调用,或者执行结果被丢弃的不必要调用会改变程序的行为

但是如果你考虑AppStut.RunnEnter不是你程序的语义的一部分,并且它的功能不依赖于它,那么你不妨忽略这个副作用。我们一直都这样,每一个真实的世界



LD计算影响了它运行的计算机的状态,当我们考虑函数的纯度时,我们选择忽略它。

但是,如果用它的返回值替换每个加调用,它总是为0,因为运行总数永远不会发生突变。add的结果完全不依赖于输入。@ftor感谢您的回复。我不太明白。add的返回值不受runningTotal的影响。另外,add的结果完全依赖于它的输入x和yYes,它依赖于输入,我的错误。但是,如果用返回值替换add,则runningTotal永远不会递增。这是行为上的改变。Bergi指出,只要程序的其他部分不依赖于runningTotal,这是无害的。但是,如果用返回值替换每个add调用,它将始终为0,因为runningTotal永远不会发生变异。add的结果完全不依赖于输入。@ftor感谢您的回复。我不太明白。add的返回值不受runningTotal的影响。另外,add的结果完全依赖于它的输入x和yYes,它依赖于输入,我的错误。但是,如果用返回值替换add,则runningTotal永远不会递增。这是行为上的改变。Bergi指出,只要程序的其他部分不依赖于runningTotal,这是无害的。完全同意,RT是一个理想的属性,但如果它是本地的或者你知道你在做什么,你可以破坏它。但是,如果编译器/解释器依赖于RT来进行进一步的优化,这是不适用的。@ For在这种情况下,编译器/解释器需要遵循它需要考虑副作用的规范,这可能是RT不同于程序员想要考虑的模型。对于EcmaScript,类似appState.runningTotal+=total的赋值;当然不能忽视,功能不纯正。非常感谢您的回复!你觉得“TheInnerLight”怎么样?我问过他同样的问题,因为他们不一样。再次感谢@他说得对。函数的副作用是递增,而替换会改变程序的行为。我只是更具体地说:如果递增或不运行总数不会改变程序的行为,那么您仍然可以认为它是纯的。@ CaseMeLeX同样,2 + 3可能被认为是纯操作。但是,如果用5代替它,程序现在的执行方式就不同了——它可能运行得更快,一个跟踪程序可以少算一个加法。我们是否认为差异是程序行为的一个改变,我们只能决定。完全同意,RT是一个理想的属性,但是如果它是本地的,或者你知道你在做什么,你可以打破它。但是,如果编译器/解释器依赖于RT来进行进一步的优化,这是不适用的。@ For在这种情况下,编译器/解释器需要遵循它需要考虑副作用的规范,这可能是RT不同于程序员想要考虑的模型。对于EcmaScript,类似appState.runningTotal+=total的赋值;当然不能忽视,功能不纯正。非常感谢您的回复!你觉得“TheInnerLight”怎么样?我问过他同样的问题,因为他们不一样。再次感谢@他说得对。函数的副作用是递增,而替换会改变程序的行为。我只是更具体地说:如果递增或不运行总数不会改变程序的行为,那么您仍然可以认为它是纯的。@ CaseMeLeX同样,2 + 3可能被认为是纯操作。但是,如果用5代替它,程序现在的执行方式就不同了——它可能运行得更快,一个跟踪程序可以少算一个加法。我们是否认为这个差异是程序行为的一个改变,我们只能决定。定义2 -给定一些输入,它总是产生相同的输出-那么不正确?或者至少是不完整的?这似乎是最普遍的定义,从我的理解来看,它直接影响了答案。谢谢你的回答-你觉得@Bergi的怎么样?我要问他和你一样的问题,因为他们不一样。再次感谢@人们经常谈论为相同的输出提供相同的输入,但这确实是一个不完整的定义。关于引用透明度的关键点是执行值替换的能力,因此没有副作用。但从逻辑上讲,如果函数是引用透明的,那么它必须为相同的输入返回相同的输出。这有助于澄清问题。一些人说,如果appState.runningTotal没有在程序的其他地方使用,那么add是透明的。你同意吗?再次感谢你,这个问题在这一点上很有哲理。这取决于你选择做什么
包括在您对程序行为的定义中。它可能会导致执行不同的代码,尽管如果从未使用过,可能会被聪明的编译器优化掉。我可能仍然认为它不是透明的,因为副作用仍然存在于您自己的代码中。我会将编译器创建的副作用放在不同的类别中,因为它们不存在于代码中,并且希望以一种可预测的方式运行。定义2-给定一些输入,它将始终生成相同的输出-是否不正确?或者至少是不完整的?这似乎是最普遍的定义,从我的理解来看,它直接影响了答案。谢谢你的回答-你觉得@Bergi的怎么样?我要问他和你一样的问题,因为他们不一样。再次感谢@人们经常谈论为相同的输出提供相同的输入,但这确实是一个不完整的定义。关于引用透明度的关键点是执行值替换的能力,因此没有副作用。但从逻辑上讲,如果函数是引用透明的,那么它必须为相同的输入返回相同的输出。这有助于澄清问题。一些人说,如果appState.runningTotal没有在程序的其他地方使用,那么add是透明的。你同意吗?再次感谢你,这个问题在这一点上很有哲理。这取决于您选择在程序行为定义中包含哪些内容。它可能会导致执行不同的代码,尽管如果从未使用过,可能会被聪明的编译器优化掉。我可能仍然认为它不是透明的,因为副作用仍然存在于您自己的代码中。我将把编译器产生的副作用放在另一个类别中,因为它们不存在于代码中,希望它们的行为是可预测的。谢谢你的回复。那么这是否意味着函数引用透明根据你所说的,我想答案是“不”。谢谢你的回答。那么这是否意味着函数引用透明根据你所说的,我认为答案是“不”。