【问题标题】:What is the difference between an Idempotent and a Deterministic function?幂等函数和确定性函数有什么区别?
【发布时间】:2016-10-28 00:29:22
【问题描述】:

它们(幂等函数和确定性函数)是否都只是在给定相同输入的情况下返回相同结果的函数?

或者我缺少什么区别? (如果有区别,请您帮我理解它是什么)

【问题讨论】:

    标签: deterministic idempotent


    【解决方案1】:

    更简单的说法:

    • 纯确定性函数:输出完全且仅基于输入值,没有其他任何东西:没有其他(隐藏的)输入或状态可用于生成其输出。没有副作用或其他输出。
    • 不纯确定性函数:与作为纯函数的确定性函数一样:输出完全且仅基于输入值,没有其他内容:没有其他(隐藏)输入或状态可以它依赖于生成其输出 - 然而还有其他输出(副作用)。
    • 幂等性:实际定义是您可以安全地多次调用同一个函数,而不必担心负面影响。更正式地说:在随后的相同调用之间没有状态变化

    幂等性并不意味着确定性(因为函数可以在第一次调用时改变状态,而在后续调用中是幂等的),但所有纯确定性函数本质上都是幂等的(因为在调用之间没有保持内部状态)。不纯的确定性函数不一定是幂等的。

    Pure deterministic Impure deterministic Pure Nondeterministic Impure Nondeterministic Idempotent
    Input Only parameter arguments (incl. this) Only parameter arguments (incl. this) Parameter arguments and hidden state Parameter arguments and hidden state Any
    Output Only return value Return value or side-effects Only return value Return value or side-effects Any
    Side-effects None Yes None Yes After 1st call: Maybe.
    After 2nd call: None
    SQL Example UCASE CREATE TABLE GETDATE DROP TABLE
    C# Example String.IndexOf DateTime.Now Directory.Create(String)Footnote1
    • Footnote1 - Directory.Create(String) 是幂等的,因为如果目录已经存在,它不会引发错误,而是返回一个新的 DirectoryInfo 实例,指向指定的现存文件系统目录(而不是 创建 首先是文件系统目录,然后返回一个指向它的新 DirectoryInfo 实例)——这就像 Win32 的 CreateFile 可用于打开现有文件。

    关于非标量参数this 和可变输入 参数的临时说明:

    (我目前不确定 OOP 语言中的实例方法(带有隐藏的 this 参数)如何分类为纯/不纯或确定性 - 尤其是 this 的目标 - so I've asked the experts in CS.SE to help me come to an answer - 一旦我得到满意的答案,我会更新这个答案。

    关于例外的说明

    当今许多(大多数?)编程语言将抛出的异常视为单独的“种类”返回(即“return 到最近的catch”)或显式副作用 (通常是由于该语言的运行时工作方式)。但是,就这个答案而言,给定函数抛出异常的能力不会改变其纯/不纯/确定性/非确定性标签 - 同上幂等性(事实上:抛出通常是如何幂等性首先实现例如,一个函数可以通过在它进行这些状态更改之前简单地抛出来避免引起任何副作用 - 但或者它也可以简单地return)。)。 p>

    因此,出于我们CS 理论 的目的,如果给定函数可以 抛出异常,那么您可以将异常视为该函数输出的简单部分。 重要是异常是否被确定性地抛出,以及是否(例如List<T>.get(int index)确定性地抛出如果index < 0)。

    注意are very different for functions that catch exceptions,然而。

    纯函数的确定性

    例如,在 SQL UCASE(val) 或 C#/.NET 中 String.IndexOf 都是确定性的,因为输出仅取决于输入。请注意,在实例方法(例如 IndexOf)中,实例对象(即隐藏的 this 参数)算作输入,即使它是“隐藏的”:

    "foo".IndexOf("o") == 1 // first cal
    "foo".IndexOf("o") == 1 // second call
    // the third call will also be == 1
    

    而在 SQL NOW() 或 C#/.NET 中 DateTime.UtcNow 不是确定性的,因为即使输入保持不变,输出也会发生变化(请注意,.NET 中的属性获取器等同于不接受任何参数的方法隐含的this 参数):

     DateTime.UtcNow == 2016-10-27 18:10:01 // first call
     DateTime.UtcNow == 2016-10-27 18:10:02 // second call
    

    幂等性

    .NET 中的一个很好的例子是Dispose() 方法:参见Should IDisposable.Dispose() implementations be idempotent?

    Dispose 方法应该可以多次调用而不会引发异常。

    因此,如果父组件Xfoo.Dispose() 进行初始调用,那么它将调用处置操作,X 现在可以考虑处置foo。执行/控制然后传递给另一个组件Y,它也尝试处理foo,在Y 调用foo.Dispose() 之后,它也可以期望foo 被处理(它是),即使@987654367 @ 已经处理了它。这意味着Y 不需要检查foo 是否已被释放,从而节省了开发人员的时间 - 并且还消除了第二次调用Dispose 可能引发异常的错误。

    另一个(一般)示例在 REST 中:HTTP1.1 的 RFC 声明 GETHEADPUTDELETE 是幂等的,但 POST 不是(https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

    方法还可以具有“幂等性”,因为(除了错误或过期问题)N > 0 个相同请求的副作用与单个请求相同。 GET、HEAD、PUT 和 DELETE 方法共享此属性。此外,方法 OPTIONS 和 TRACE 不应该有副作用,因此本质上是幂等的。

    所以如果你使用DELETE 那么:

    Client->Server: DELETE /foo/bar
    // `foo/bar` is now deleted
    Server->Client: 200 OK
    Client->Server DELETE /foo/bar
    // foo/bar` is already deleted, so there's nothing to do, but inform the client that foo/bar doesn't exist
    Server->Client: 404 Not Found
    // the client asks again:
    Client->Server: DELETE /foo/bar
    // foo/bar` is already deleted, so there's nothing to do, but inform the client that foo/bar doesn't exist
    Server->Client: 404 Not Found
    

    所以你在上面的例子中看到DELETE是幂等的,因为服务器的状态在最后两个DELETE请求之间没有改变,但它不是确定性的,因为服务器返回了第一个200请求但 404 用于第二个请求。

    【讨论】:

    • 如果您只考虑输出而不考虑算法,那么您定义的确定性函数并不总是幂等的。例如,当存在全局变量时,由int f(x) { i = i+1; return 42; } 定义的程序中的函数f(即f 总是返回42,但递增一个全局变量a)是确定性的,但不是幂等的。也许这篇文章中“确定性”和“纯粹”混淆了。
    • @Dai 你将如何调用一个无论如何都会确保结果相同的函数。 - 例如,无论机器在 ec2 上的状态如何,它都会确保您的服务器最终是健康的.. ?
    • @Dai 我也同意deterministic 本身并不意味着idempotent 这一事实。如果您有一个基于相同输入生成相同输出但有副作用的函数怎么办? Idk 例如,它在其中执行另一个函数调用,改变其他地方的某些状态,或修改可变数据类型等(并不是说这将是一个好的设计,实际上它是一个糟糕的设计,它应该是一直避免),但它表明它不是idempotent。我会说你的定义是正确的,但后一种说法是不正确的。
    • @George 你是对的 - 我应该区分纯确定性函数和不纯确定性函数。我已经修改了答案。
    • @Davos CREATE TABLE IF NOT EXISTS 是不纯的非确定性和幂等的。我不熟悉CREATE OR REPLACE TABLE 的语义,但我认为即使架构相同,它也会始终删除/覆盖表?如果是这样,那么CREATE OR REPLACE TABLE 将是不纯的非确定性的,但仅在不切实际的学术纯数据库系统中是幂等的 - 实际上,此操作不是幂等的,因为它在数据库引擎的其他地方运行时每次都会改变状态(例如磁盘上的存储页面、统计信息、计数器/指标、审计日志等。
    【解决方案2】:

    确定性函数只是数学意义上的函数。给定相同的输入,您总是得到相同的输出。另一方面,幂等函数是满足恒等式的函数

    f(f(x)) = f(x) 
    

    作为一个简单的例子。如果UCase()是一个将字符串转换为大写字符串的函数,那么显然UCase(Ucase(s)) = UCase(s)

    幂等函数是所有函数的子集。

    【讨论】:

    • 计算机科学意义上的呢?考虑一个更新状态的函数,例如数据库表。将输入数据和表的状态表示为单独的输入f(x, y) 可能是合适的,所以在表已经存在的情况下,f(x, f(x, y)) = f(x, y) ...哦...是不同的还是我只是绕道到达同一个f(f(x)) = f(x) 的方法?
    【解决方案3】:

    无论您调用多少次,确定性函数都会为相同的输入返回相同的结果。

    idempotent 函数可能不会返回相同的结果(它会以相同的形式返回结果,但值可能不同,请参见下面的 http 示例)。它只保证它不会有副作用。换句话说,它不会改变任何东西。

    例如,GET 动词在 HTTP 协议中是幂等的。如果您调用“~/employees/1”,它将以特定格式返回 ID 为 1 的员工的信息。它不应该改变任何东西,而只是简单地返回员工信息。如果您调用它 10、100 次左右,返回的格式将始终相同。但是,它绝不可能是确定性的。也许如果您第二次调用它,则员工信息已更改,或者该员工甚至不再存在。但绝不应该有副作用或以不同的格式返回结果。

    我的意见

    幂等是一个奇怪的词,但知道起源会很有帮助,idem 意思是 samepotent 意思是 power时间>。换句话说,它意味着具有相同的力量,这显然并不意味着没有副作用,所以不确定它来自哪里。 计算机科学中只有两个困难的事情,缓存失效和命名事情。他们为什么不能只使用只读?哦等等,他们想听起来更聪明,也许?或许像圈复杂度

    【讨论】:

    • 有 4 件困难的事情:0. 缓存失效 1. 命名事物 2. 仅一次交付 3. 仅一次交付 4. 一个错误
    • @Davos “世界上有 10 种人:懂二进制的和不懂二进制的。”
    猜你喜欢
    • 1970-01-01
    • 2015-03-15
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 2016-04-24
    • 2019-01-25
    • 2010-12-14
    • 2021-04-13
    相关资源
    最近更新 更多