如果纯函数组合,你的领域模型(或者至少是有纯函数的模型的一部分)应该表现出一些数学性质,对吗?至少当我在鼓励使用纯函数来建模时,我的想法是这样的。在这一章里,你将尝试去弄清楚是否你可以论证模型的一些属性并检查其正确性,正如你在数学上所能做的那样。这就是所谓的equational reasoning(方程式推理),在后面的章节中你会看到很多例子。
考虑一下清单1.6中的定义,我们将debit和credit实现为纯函数。使用这个模型,你可以写验证你的实现的断言。这些叫做模型的properties,下面的代码片段提供了模型正确性的验证。你从在一个账户中执行一个credit(存款)和一个等量的debit(取款)的表达式开始。当然,在执行表达式之前,你还需要给你的账户以原始余额。为了验证这个property,您可以在派生的每个步骤中替换我们的实现(就像你解一个数学方程的时候),并最终到达您的结果。
你在这个推导过程中得到了什么?你证明了一个显而易见的引理,对同一账户x存款与取款相同的值,不会改变账户的初始余额。很明显,不是吗?
问1.7:对与错:方程式推理和副作用不会在一起。
当你处理函数调用时,它看起来很明显,就像你在数学中所做的那样。您将一个函数调用替换为它的实现,并期望获得相同的结果,而不管您执行这个操作的次数。让我们来考虑一下清单1.12中的例子。在这个例子中,你追踪f(5)的函数调用,通过不断地以函数的主体和对应的形参的值去替换函数调用。
正如你所看到的,通过使用替换模型,与每次你用5这个参数去调用f函数,你得到的结果是相同的。但是请注意,只有当函数是纯的且没有未管理的副作用时,替换模型才会起作用。如果函数的平方在返回值的同时写入文件,那么就会产生副作用,因为文件写操作在某些调用上可能会失败,而函数会产生一个异常。因此,在每次调用时产生相同结果的替代模型的保证都是无效的。这是另一个支持纯函数的原因。
答1.7:True.正如之前所讨论的,副作用导致了计算的不确定性,你不能用它们来做方程式推理
与替换模型相关的是我在本书中反复强调的另一个概念。像f(5)这样的表达式每次当你将值5代入函数的形参时产生相同的输出结果是如此重要,以致于它们有一个特殊的术语:引用透明的表达式。它们在函数式编程的世界中扮演着重要的角色。正如您在本节中看到的那样,您可以仅使用引用透明的表达式来进行方程式推理。
那么,我们以函数和响应性建模领域的路线图在哪里呢?以下是本节的结论:
引用透明的表达式是纯的。
引用透明的表达式使替换模型工作。
替换模型有助于方程式推理。
图1.9总结了函数式编程的三大支柱。
到目前为止我们所讨论的关于函数式编程的基本原则,可以帮助我们设计一个更好的领域模型----更好的是,你可以制作你的模型。
用函数组合的力量来构建更大的函数
纯,在你的模型的很多部分,都可以使用引用透明的表达式组成,它具有很多优秀的优点,这个我们刚才讨论了。
很容易推理,且可以通过方程式推理来验证许多领域行为
接下来的小节专注于一个方面,它可以使你的模型更加灵敏。用户不喜欢在查询账户余额或在银行排队打开支票账户时等待很长时间。您的软件需要在合理的时间内响应所有用户的操作,通常称为latency(延迟)。它是reactive(响应性)的属性,它使你的模型在一个限界的延迟的情况下工作。