What is a “side effect?”

函数的副作用

​ 人们都说,一个纯粹的函数式程序是没有副作用的。那么什么是副作用呢?

​ Wikipedia中是这样描述的:“在计算机科学中,函数副作用指当调用函数时,除了返回函数值之外,还对主调用函数产生附加的影响。”

​ 例如修改全局变量(函数外的变量)或修改参数。函数副作用会给程序设计带来不必要的麻烦,给程序带来十分难以查找的错误,并降低程序的可读性。严格的函数式语言要求函数必须无副作用。

​ 副作用包括以下内容:

  • IO输出
  • IO读
  • 修改一个参数的状态,修改一个数据结构中的数据,或者修改一个对象的某个属性的值
  • 抛出异常,或者当错误发生时停止整个程序
  • 调用了其他有副作用的函数

    ​下面是函数的副作用相关的几个概念,纯函数(Pure Function)、非纯函数(Impure Function)、引用透明(Referential Transparent)。

纯函数(Pure Function)

​ ——输入输出数据流全是显式(Explicit)的。

​ 显式(Explicit)的意思是,函数与外界交换数据只有一个唯一渠道——参数和返回值;函数从函数外部接受的所有输入信息都通过参数传递到该函数内部;函数输出到函数外部的所有信息都通过返回值传递到该函数外部。

非纯函数

​ 如果一个函数通过隐式(Implicit)方式,从外界获取数据,或者向外部输出数据,那么,该函数就不是纯函数,叫作非纯函数(Impure Function)。

​ 隐式(Implicit)的意思是,函数通过参数和返回值以外的渠道,和外界进行数据交换。比如,读取全局变量,修改全局变量,都叫作以隐式的方式和外界进行数据交换;比如,利用 I/O API(输入输出系统函数库)读取配置文件,或者输出到文件,打印到屏幕,都叫做隐式的方式和外界进行数据交换。

​ I/O API 可以看作是一种特殊的全局变量。文件、屏幕、数据库等输入输出结构可以看作是独立于运行环境之外的系统外全局变量,而不是应用程序自己定义的全局变量。

​ 纯函数内部有隐式(Implicit)的数据流,这种情况叫做副作用(Side Effect)。上述的I/O,外部变量等,都可以归为副作用。因此,纯函数的定义也可以写为“没有副作用的函数”。

引用透明

​ 引用透明(Referential Transparent)的概念与函数的副作用相关,且受其影响。如果程序中任意两处具有相同输入值的函数调用能够互相置换,而不影响程序的动作,那么该程序就具有引用透明性。它的优点是比非引用透明的语言的语义更容易理解,不那么晦涩。纯函数式语言没有变量,所以它们都具有引用透明性。

特殊的函数副作用

​ 上述只讨论了一般的情况,还有一种特殊的情况,我们没有讨论。有些函数的参数是一种 In/Out 作用的参数,即函数可能改变参数里面的内容,把一些信息通过输入参数,夹带到外界。这种情况,严格来说,也是副作用。也是非纯函数。 比如下面的函数。

纯函数的特征

​ 理论上,无副作用的函数更容易被测试。假设有一个把值相加的函数,如 + 。给定数字1和2,结果必定是3。一个像这样的无副作用的函数有如下特征:+

  • 输入不可变
  • 结果一致
  • 没有任何其他操作

纯函数的优点

  • 无状态。线程安全。不需要线程同步。
  • 纯函数相互调用组装起来的函数,还是纯函数。
  • 应用程序或者运行环境(Runtime)可以对纯函数的运算结果进行缓存,运算加快速度。
    因为这样的函数没有副作用,它很容易被测试。

知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。

发表评论

电子邮件地址不会被公开。 必填项已用*标注