幂等函数和纯函数是相同的吗?

75

我阅读了维基百科有关幂等性的解释。 我知道这意味着一个函数的输出由其输入决定。 但我记得我听说过一个非常相似的概念:纯函数。 我用谷歌搜索它们,但找不到它们之间的区别......

它们是等价的吗?


2
以下是有关编程的内容,从英语翻译成中文。仅返回翻译后的文本:这可能对想要理解概念的人有用:http://pedrorijo.com/blog/fp-concepts/ - pedrorijo91
根据这个带有示例的优秀答案(转述):对于没有副作用(纯函数)的函数,幂等性意味着对于所有的x值,f(x) = f(f(x)) = f(f(f(x))) = f(f(f(f(x)))) = ...... 对于有副作用的函数,幂等性还意味着在第一次应用后不会引起任何其他副作用。如果您愿意,可以将世界的状态视为函数的另一个“隐藏”参数。 - toraritte
但是,从纯函数是否幂等?中得出的结论是:“仅当纯函数返回f(f(x)) === f(x)时才是幂等的,这种情况只有在函数不返回任何内容时才会发生。一个很好的例子是double(x),而且很明显double(double(x)) !== double(x)”。 - toraritte
7个回答

77

幂等函数可能会引起幂等性副作用。

纯函数不会。

例如,设置文本框文本的函数是幂等的(因为多次调用会显示相同的文本),但不是纯函数。
同样,通过GUID删除记录(而不是通过计数)是幂等的,因为在后续调用中行保持删除状态。(额外的调用没有任何影响)


幂等副作用的例子是什么?这是否类似于向标准输出打印内容? - Rafe Kettler
@Rafe:更改数据库。例如,更改记录中的字段。 - Robert Harvey
1
@Rafe:向标准输出打印并不是幂等的,因为每次调用都会打印出另一行。 - SLaks
在我看来,删除一条记录的副作用是不幂等的。你不能删除两次。 - leppie
1
@leppie:但是在调用函数两次后,没有任何变化。因此,它是幂等的。例如,HTTP的“DELETE”动词。 - SLaks
5
只要删除操作没有出错,删除就是幂等的——一个应用后的世界状态与两次应用后相同——行已被删除。只要在调用n>=1次后,世界状态和结果与一次调用后相同,按定义,它就是幂等的。但如果它报错了,就不是幂等的,例如如果它在错误时打印到stderr。 - tobyodavies

24

一个纯函数是一种没有副作用的函数,其输出仅由输入决定 - 也就是说,调用f(x)无论调用多少次都会给出相同结果。

幂等函数是指可以重复应用而不改变结果的函数 - 也就是说,f(f(x))f(x)相同。

一个函数可以是纯函数、幂等函数、二者皆是或两者都不是。


11
但是一个纯函数 必须 是幂等的。 - SLaks
4
不,他的解释在计算领域是有效的。然而,在Anon的回答中,改变的计算状态是输出的一部分。 - Brian
22
不正确。f(x) = x+1 不是幂等的,因为 f(f(1)) != f(1) - porges
2
@nilskp 纯度是与幂等性不同的概念;您似乎误解了它的定义。幂等性意味着对操作或函数进行额外的连续组合(在第一个函数应用的输出上),将不会产生不同的输出,即 f(x) = f(f(x)) = f(f(f(x))) = ... 等等。纯度意味着相同的输入(而不是任何先前应用的输出)将给出相同的输出,无论时间或外部世界的状态如何。 - dxuhuang
3
在命令式编程语言中,一个由调用f(x)组成的语句是对一个假设函数(不是f)的调用,该函数将“世界状态”作为输入并在调用返回时输出不同的状态。如果第一次调用后再次调用f(x)不会改变任何东西,则可以将f(x)称为幂等的。 - dxuhuang
显示剩余6条评论

10

不,幂等函数会改变程序/对象/机器的状态 - 并且尽管重复调用,它只会进行一次更改。纯函数不改变任何东西,并且每次调用时都会提供(返回)结果。


6

功能纯度意味着没有副作用。另一方面,幂等性意味着一个函数对于多次调用是不变的。

每个纯函数都是副作用幂等的,因为纯函数即使被多次调用也永远不会产生副作用。然而,返回值的幂等性意味着f(f(x)) = f(x),这与纯度无关。


4
在计算机科学中,idempotence似乎在命令式编程和函数式编程中有不同的定义,这是一个很大的困惑之源。
来自维基百科(链接1),在计算机科学中,“idempotent”一词用于更全面地描述一种操作,即无论执行一次还是多次,都会产生相同的结果。这可能因应用环境而异。例如,在具有副作用的方法或子程序调用的情况下,它意味着修改后的状态在第一次调用后保持不变。然而,在函数式编程中,idempotent函数是指对于任何值x,具有f(f(x)) = f(x)属性的函数。
由于纯函数不会产生副作用,因此我认为idempotence与纯度无关。

0
定义:
- 纯函数:对于给定的 x,f(x) 总是返回相同的值。 - 幂等函数:f(f(x)) = f(x)。

例子

不纯,不幂等

def f(x):
    return random()

检查:
f(0) = 0.2171
f(0) = 0.3142       # Thus, impure.

纯粹,但不是幂等的
def f(x):
    return x + 1

检查:
f(0) = 1
f(0) = 1  # Thus, pure.
f(1) = 2  # Thus, not idempotent since f(0) != f(f(0)).

纯净且幂等
def f(x):
    return round(x)

检查:
f(0.3142) = 0
f(0.3142) = 0  # Thus, pure.
f(0) = 0       # Thus, idempotent.

0

我发现更多地方将“幂等”定义为f(f(x)) = f(x),但我真的不相信这是准确的。相反,我认为这个定义更准确(但不完全):

描述一种行为,当在同一主题上执行多次时,在第一次执行后对其主题没有进一步影响。投影算子是幂等的。

我的理解是,如果我们像下面这样两次应用fx(主题):

f(x);f(x);

那么(副作用)效果与

f(x);

相同。因为纯函数不允许副作用,所以纯函数也是“幂等”的。


更一般(也更准确)的幂等定义还包括像

toggle(x)

我们可以说,toggle幂等度为2,因为在应用toggle每2次后,我们总是得到相同的状态


实际上,f(x) = f(f(x)) 绝对是对幂等性的严谨而准确的定义。在你提到的例子中,"f(x); f(x);f(x) 具有相同的副作用" 被展示为 "幂等性",但幂等函数并不是 f... 它是一个隐藏的名为 call_f_x 的函数 作用于真实世界的状态。然后,call_f_x(call_f_x(state)) = call_f_x(state)。这确实是幂等函数的确切定义。 - undefined
...附言:这种对不纯净的“状态”的明确表述类似于Haskell如何强制程序员在纯函数中建模副作用。尽管“状态”发生了“副作用”,但call_f_x是纯粹的。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接