目录
在学习 React/Redux 的时候,提到了纯函数,那么到底什么是纯函数呢?
简介
纯函数,顾名思义就是很纯净的函数,不会背着你去干什么乱七八糟的事情。
简而言之,就是这个与外界交换数据的方式只有 参数值
和 返回值
。
也就是说,所有的数据输入和输出都是显式的,都在你的可监控范围之下。
定义
首先纯函数要满足以下两个条件:
函数在给出相同的参数的时候,计算的值总是相同的。同时函数的结果并不依赖任何可能随着程序运行而改变的或者在不同程序中结果不同的隐藏的信息或者状态。也不能隐式依赖任何从 I/O 设备的输入。
这些计算结果不能引起任何副作用或者输出。例如改变可变对象,或者是输出到 I/O 设备。
计算结果不需要全部依赖输入的参数值。但是,绝对不能依赖除了参数值以外的东西。
函数可以返回多重结果(类似py里的元组),那么对于任意一个返回值,都需要满足上面的条件。(这个感觉显得有点多余)
如果其中的参数是被引用的,那么修改引用的参数将会导致外部变量修改,从而导致函数变得非纯。(这不是废话么)
解释
看上面的那几条,肯定会变得很糊涂,那么我稍微总结了以下内容:
最最基本的判定方法,就是看参数相同是否结果相同。不相同,是非纯函数。
在满足
1
的前提下,同时保证输入相同,并且这个函数不管在什么地方,是什么时候运行,结果都并不是完全相同。那么则为非纯函数。那么意味着函数内不得使用获取时间,获取进程ID,获取环境变量等等会根据时间环境而变化的内容。例如Date.now()
process.env
Math.random()
换句话说,纯函数内不得使用非纯函数
纯函数不得与 I/O 产生任何交互,不得从 I/O 输入或者输出,甚至包括网络流。 也就说不能读取输出文件,读取输出终端内容,不得请求API内容等等,前提,这些是隐式调用的,后文会讲到特例。
不得产生函数副作用,所谓函数副作用就是指当调用函数时,除了返回函数值之外,还对主调用函数产生附加的影响。例如修改全局变量(函数外的变量)或修改参数。
I/O 在纯函数中的例外
如果一个函数跟 I/O 产生交互,除非满足以下内容,才不会导致函数变的不纯:
这些 I/O 操作是显式通过函数参数或者返回值来传入和传出的,并且当输入内容不合法的时候,I/O 操作失败
其中第一点确保了 I/O 操作的函数返回不同值,是因为输入的内容不同。并且必须要作为函数的参数或者返回值。
第二点确保了当输入作为函数的参数的时候,必须根据不同的 I/O 动作而改变。也就是针对不同的输入有不同的反应。
说明一下,这里的第二点,其实是保证了函数的行为的可预测性,因为输入不同,可能其中包含着很多非法操作,而对于函数来说,面对这些非法操作,没有定义如何去处理,所以统一认为操作失败,这样就增加了行为的可预测性。
和纯函数相关的 —— 纯表达式
简介
类似一个纯函数,就是不论在什么时候,什么地点,执行了多少次纯表达式,结果都不变。
在这里,我就不详细介绍了,很明显的一点,一个常量肯定是纯表达式。
用处
讲了这么多,可是纯表达式在什么地方会使用到呢?
就我所知,大约有以下几个地方:
Redux 的 Reducer
Scala
wolfarm
优点
优点在不同的语言中有不同的用处,但是最重要的几点就是:
简单,便于测试
无状态,可以采用缓存的方式加速计算
纯函数相互组合,还是纯函数(类似于高中所学的奇函数偶函数)