纯纯的函数
纯函数是这样一种函数,即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。
作用 本身并没什么坏处,而且在本书后面的章节你随处可见它的身影。副作用 的关键部分在于 副。就像一潭死水中的“水”本身并不是幼虫的培养器,死 才是生成虫群的原因。同理,副作用中的 副 是滋生 bug 的温床。
副作用是在计算结果的过程中,系统状态的一种变化,或者与外部世界进行的可观察的交互。
副作用可能包含,但不限于
- 更改文件系统
- 往数据库插入记录
- 发送一个 http 请求
- 可变数据
- 打印 / log
- 获取用户输入
- DOM 查询
- 访问系统状态
这个列表还可以继续写下去。概括来讲,只要是跟函数外部环境发生的交互就都是副作用——这一点可能会让你怀疑无副作用编程的可行性。函数式编程的哲学就是假定副作用是造成不正当行为的主要原因。
这并不是说,要禁止使用一切副作用,而是说,要让它们在可控的范围内发生。后面讲到 functor 和 monad 的时候我们会学习如何控制它们,目前还是尽量远离这些阴险的函数为好。
副作用让一个函数变得不纯是有道理的:从定义上来说,纯函数必须要能够根据相同的输入返回相同的输出;如果函数需要跟外部事物打交道,那么就无法保证这一点了。
追求 纯 的理由
可缓存性(Cacheable)
纯函数总能够根据输入来做缓存。
可移植性/自文档化(Portable / Self-Documenting)
纯函数的依赖很明确,因此更易于观察和理解——没有偷偷摸摸的小动作;
通过强迫“注入”依赖,或者把它们当作参数传递,我们的应用也更加灵活;
在 JavaScript 的设定中,可移植性可以意味着把函数序列化(serializing)并通过 socket 发送。也可以意味着代码能够在 web workers 中运行。总之,可移植性是一个非常强大的特性。
可测试性(Testable)
纯函数让测试更加容易。我们不需要伪造一个“真实的”支付网关,或者每一次测试之前都要配置、之后都要断言状态(assert the state)。只需简单地给函数一个输入,然后断言输出就好了。
函数式编程的社区正在开创一些新的测试工具,能够帮助我们自动生成输入并断言输出。强烈推荐 Quickcheck——一个为函数式环境量身定制的测试工具。
引用透明性(referential transparency)
如果一段代码可以替换成它执行所得的结果,而且是在不改变整个程序行为的前提下替换的,那么我们就说这段代码是引用透明的。
我们可以使用一种叫做“等式推导”(equational reasoning)的技术来分析代码。所谓“等式推导”就是“一对一”替换,有点像在不考虑程序性执行的怪异行为(quirks of programmatic evaluation)的情况下,手动执行相关代码。
等式推导带来的分析代码的能力对重构和理解代码非常重要。
并行代码
可以并行运行任意纯函数。因为纯函数根本不需要访问共享的内存,而且根据其定义,纯函数也不会因副作用而进入竞争态(race condition)。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论