什么是函数架构?


函数架构是指一个架构中主要部分是纯函数,且纯函数不能调用不纯的活动;但是不纯的活动能够调用纯函数。
那么什么是纯函数?就是引用透明,为了使函数具有引用透明性(也称为纯函数),它必须具有两个属性:

  • 它必须始终对同一输入返回相同的输出。我们称之为质量决定论。
  • 它必须没有副作用。 

比如对于表达式,等号的左手边和右手边是真正相等的:
two = 1 + 1

Haskell中,这是由编译器强制执行的,“=”真正意味着相等。在C#,Java和其他命令式语言中,“=”暗示赋值,而不是相等。

如果代码是引用透明的,那么您可以使用左侧的符号替换右侧的表达式:
i = findBestNumber [42,1337,2112,90125]

FP中的所有其他内容都遵循此定义。例如,值必须是不可变的,因为如果它们不是,你可以改变它们,这将被视为副作用。

我更喜欢这个定义的原因是它支持伪证法。你可以断言函数或值是纯粹的; 所需要的只是一个反例来证明它不是。反例可以是一个对于同样输入值不总是产生相同返回值的例子,也可以是产生副作用的函数调用的例子。

所有软件都会产生副作用:更改显示器上的像素是一个副作用。将字节写入磁盘是一个副作用。通过网络传输一点是副作用。

假设你有两组操作:不纯的活动和纯函数。

纯函数:虽然有纯函数的规则,但这些规则仍然允许交互。一个纯函数可以调用另一个纯函数。这种交互不会改变任何这些功能的属性。调用者和被调用者都保持无副作用和确定性。

不纯活动:不纯的活动也可以互动。没有规则适用于他们。由于没有规则适用于不纯的活动,因此它们可以调用纯函数。

不纯的活动不受规则约束,因此他们可以做任何他们需要做的事情,包括绘制像素,写入文件或调用纯函数。纯函数是确定性的,没有副作用。这些属性不会因为其输出结果会显示在屏幕上而改变。

函数架构的规则:


Caller表示调用者,Callee表示被调用者

让我们将上述规则称为函数交互法:纯函数不能调用不纯的活动。因此,函数架构是遵循该法则的代码库,并且具有很大一部分纯代码。

显然,通过编写不纯的代码,您可以轻而易举地遵守函数交互法。从某种意义上说,这是您在命令式编程语言中默认执行的操作。如果你熟悉Haskell,想象一下编写一个完整的程序IO。这是可能的,但毫无意义。

代码库的重要部分应该由纯代码组成。多少为好?越多越好。主观上,我会说代码库的一半以上应该是纯粹的。

如果有一个工具可以自动检查代码是否遵循函数交互法则会很好。我所知道的唯一强制执行函数交互法的工具是一些编程语言,最着名的是Haskell(其他也存在)。Haskell通过其IO类型强制执行函数交互法。您不能IO在纯函数(不返回的函数IO)中使用值。如果您尝试,您的代码不会编译。

我个人反复使用Haskell来理解函数架构的局限性,例如确定依赖注入不起作用因为它使一切都不纯。