在我们称之为"幂等"之前,函数究竟必须遵守哪些规则?

Pac*_*ier 9 java language-agnostic idempotent

来自另一个线程的帖子说如果一个函数可以被多次调用而不改变结果,则该函数被认为是幂等的.

然而,所使用的术语(如无副作用和返回相同结果)相对模糊.考虑一下这段代码:

public class test {

    int x = 0;
    java.util.Random r = new java.util.Random();

    public int F() {
        return x + 1;
    }

    public void F2() {
        x = r.nextInt();
    }
}
Run Code Online (Sandbox Code Playgroud)

我们可以说这F()是幂等的因为连续调用F()返回相同的值吗?

或者它是不是幂等的,因为F()如果F2()在中间调用后,连续调用不返回相同的值?

PS:计算机科学中定义的" 幂等 ",而不是数学.

Dav*_*rtz 10

我将不同意(实际上,我现在看到我同意他们!)与其他答案并说,在最常见的计算机科学中使用(带副作用的函数调用,而不是函数式编程),函数是幂等,如果您可以安全地替换函数的任何调用,并调用该函数两次并仅保留第二个结果.

例如,考虑两个按名称删除文件的功能:

1)如果文件不存在则返回成功的函数.(因为删除操作的目的是使文件不存在.)

2)如果文件不存在,则返回"文件不存在"错误的函数.(由于无法删除文件.)

第一个是幂等的.如果您调用它并忽略结果,则可以再次调用它并仍然获得正确的信息.完成后,该文件不存在.

第二个不是幂等的.如果您调用一次并忽略结果,则第二次调用将失败,使您认为您没有删除该文件.

获取当前时间的函数在此定义下是幂等的,即使结果可能不同.调用该函数两次没有坏处.

该概念在客户端 - 服务器协议中很重要.假设您发送命令并且没有得到回复,可能连接断开,也许服务器崩溃了.所以你再次发送命令并得到答复.但在第一个命令,命令丢失或回复?如果命令是幂等的,那没关系.你可以使用结果.

如果协议保证所有操作都是幂等的,则较低级别的代码可以重试失败的操作,切换服务器,以及在不破坏操作语义的情况下尝试"使工作正常".

制作幂等协议需要做一些工作.例如,您可能想知道如何进行合理的"删除文件"操作.一种方法是为每个文件分配一个唯一的ID,该ID在删除和重新创建文件时会发生变化.然后将删除分成两半.第一个"从名称获取ID"是幂等的,如果文件不存在则失败.第二个"如果存在则删除ID"是幂等的,如果您或其他任何人删除了该文件,则会成功.(一个怪癖是这并不能告诉你确定你是删除文件的人.)两个幂等操作的组合提供了所需的非幂等删除操作.

  • @DavidHeffernan:这不是缺乏想象力,而是命令式的"函数"不仅仅依赖于它的参数,而是在整个执行环境中运行.因此,如果文件不存在,则成功删除是幂等的,因为在第一次调用之后调用它两次后机器的状态是相同的.也就是说,`Del(Del(x))== Del(x)`,其中`x`是机器的初始状态.但是"ENOENT"版本并不是幂等的,因为"Del(x)"是一个返回寄存器为"0"的状态,而"Del(Del(x))"是一个"ENOENT"的状态. (4认同)
  • 是的,我认为这回答了被问到的问题.当计算机科学家没有想象力去发明他们自己的话语并且通过窃取数学家的话来弄脏水域时,我讨厌它!无论如何,+1. (2认同)
  • @SteveJessop:如果状态不同但差异没有语义相关性怎么办?一个函数不是幂等的,因为它保留了一个内部计数器,它被调用了多少次?或者,为了使它更有趣,是一个函数返回指定范围内的随机数幂等?它可以返回不同的结果,但所有结果在语义上都是有效的. (2认同)
  • 在不明显的情况下,这里的"Del"是操作,"用一些特定的参数调用delete函数",并且是将一个机器状态映射到另一个机器状态的函数.因此,滥用术语(如果有的话)是将"删除函数"描述为幂等因为我们实际意味着*调用*删除函数是幂等的. (2认同)

Ste*_*eod 5

你的功能不是幂等的.它可以返回不同的结果.给定相同的输入,幂等函数总是返回相同的输出.

更明确地说,如果f()是幂等的(根据计算机科学定义),那么:

int result1 = f(x);
// ... some arbitrary code
int result2 = f(x);
assert(result1 == result2);
Run Code Online (Sandbox Code Playgroud)

  • 另一个需要考虑的例子是函数`int f(int i){global_value + = 1; 返回0; }`.根据定义"`f(f(x))== f(x)`对于所有x",函数本身显然是幂等的.但是调用函数的操作不是幂等的,因为`global_value`的值根据你调用的次数而不同.所以,除非你能够精确地指出一个函数"是否是幂等的",并且几乎所有实际目的都是调用我们关心的函数的整个效果,而不仅仅是返回值. (3认同)
  • ...因为它让人们认为它们是所列出参数的数学函数,而它们并非如此.人们似乎很满意在OO语言中,"this"是方法的一个秘密额外参数.在*完全相同的方式中,执行环境的状态是命令式语言中每个函数的秘密额外参数,并且函数返回的点处的状态是额外输出.如果你没有把这个结合到你的模型中那么简单的定义,比如`f(f(x))== f(x)`从数学中复制粘贴将给出愚蠢的结果. (3认同)
  • 这是`idempotent`的函数式编程定义.我不认为这是最常见的计算机科学定义. (2认同)
  • ..所以`f`不是"数学上"幂等的,它是"简单且不恰当地应用定义"的幂等.但是,如果`global_value`不是一个递增的计数器,但实际上是一个用于记忆该函数的结果缓存,那是不可全局访问的,那么在某些情况下将`f`视为"它"可能是合适的.纯粹的",即使对于能够观察缓存的人来说也不纯洁. (2认同)