副作用 (计算机科学)

编辑
本词条由“匿名用户” 建档。
在计算机科学中,如果一个操作、函数或表达式在其局部环境之外修改了某些状态变量值,则称其具有副作用,也就是说,除了返回 a 的主要效果之外,它是否具有任何可观察到的效果 值给操作的调用者。 示例副作用包括修改非局部变量、修改静态局部变量、修改通过引用传递的可变参数、执行 I/O 或调用其他具有副作用的函数。 在存在副作用的情况下,程序的行为可能取决于历史; 也就是说,评估的顺序很重要。 理解和调...

计算机科学中,如果一个操作、函数或表达式在其局部环境之外修改了某些状态变量值,则称其具有副作用,也就是说,除了返回 a 的主要效果之外,它是否具有任何可观察到的效果 值给操作的调用者。 示例副作用包括修改非局部变量、修改静态局部变量、修改通过引用传递的可变参数、执行 I/O 或调用其他具有副作用的函数。 在存在副作用的情况下,程序的行为可能取决于历史; 也就是说,评估的顺序很重要。 理解和调试具有副作用的函数需要了解上下文及其可能的历史。

副作用在编程语言设计和分析中起着重要作用。 使用副作用的程度取决于编程范例。 例如,命令式编程通常用于产生副作用、更新系统状态。 相比之下,声明式编程通常用于报告系统状态,没有副作用。

函数式编程旨在最小化或消除副作用。 没有副作用使得对程序进行形式验证变得更加容易。 函数式语言 Haskell 通过将它们替换为 monadic 操作来消除 I/O 和其他有状态计算等副作用。 Standard ML、Scheme 和 Scala 等函数式语言不限制副作用,但程序员习惯于避免它们。

汇编语言程序员必须意识到隐藏的副作用——修改指令助记符中未提及的处理器状态部分的指令。 隐藏副作用的一个典型示例是一条算术指令,它隐式修改条件代码(隐藏副作用),同时显式修改寄存器(预期效果)。 具有隐藏副作用的指令集的一个潜在缺点是,如果许多指令对单个状态(如条件代码)有副作用,则按顺序更新该状态所需的逻辑可能成为性能瓶颈。 这个问题在一些设计有流水线(自 1990 年)或无序执行的处理器上尤为严重。 这样的处理器可能需要额外的控制电路来检测隐藏的副作用并在下一条指令取决于这些影响的结果时停止流水线。

引用透明

没有副作用是引用透明的必要条件,但不是充分条件。 引用透明意味着表达式(例如函数调用)可以用它的值替换。 这要求表达式是纯的,也就是说表达式必须是确定性的(总是对相同的输入给出相同的值)并且没有副作用。

暂时的副作用

在讨论副作用和引用透明性时,通常会忽略由操作执行所花费的时间引起的副作用。 在某些情况下,例如硬件时序或测试,会专门针对其暂时的副作用插入操作,例如 sleep(5000) 或 for (int i = 0; i < 10000; ++i) {}。 除了需要一定的时间才能完成之外,这些指令不会改变状态。

幂等性

如果子例程的多个应用程序对系统状态的影响与单个应用程序相同,则具有副作用的子例程是幂等的,换句话说,如果从系统状态空间到自身与子例程相关联的函数在数学意义上是幂等的。

setx 是幂等的,因为第二次将 setx 设置为 3 对系统状态的影响与xxx次应用相同:x 在xxx次应用后已设置为 3,在第二次应用后仍设置为 3。

如果纯函数在数学意义上是幂等的,则它是幂等的。 例如,考虑以下 Python 程序:

def abs(n): 如果 n < 则返回 -n 0 else nassert abs(abs(-3)) == abs(-3)

abs 是幂等的,因为第二次应用 abs 到xxx次应用到 -3 的返回值与xxx次应用到 -3 返回相同的值。

副作用 (计算机科学)

例子

副作用行为的一个常见演示是 C 中的赋值运算符。赋值 a = b 是一个计算结果与表达式 b 相同的值的表达式,具有将 b 的 R 值存储到 L 中的副作用 -a 的值。 这允许多重分配:

一 = (b = 3); // b = 3 计算结果为 3,然后将其分配给 a

因为运算符关联,这相当于

一 = b = 3;

这对新手程序员来说是一个潜在的障碍,他们可能会混淆

while (b == 3) {} // 测试 b 是否等于 3

内容由匿名用户提供,本内容不代表vibaike.com立场,内容投诉举报请联系vibaike.com客服。如若转载,请注明出处:https://vibaike.com/195617/

(1)
词条目录
  1. 副作用 (计算机科学)
  2. 引用透明
  3. 暂时的副作用
  4. 幂等性
  5. 例子

轻触这里

关闭目录

目录