最近我读了很多关于函数式编程的东西,大部分我都能理解,但有一件事我就是搞不懂,那就是无状态编码。在我看来,通过删除可变状态来简化编程就像通过删除仪表盘来“简化”一辆汽车:最终产品可能更简单,但希望它能与最终用户交互。
几乎我能想到的每个用户应用程序都将状态作为核心概念。如果你写了一个文档(或一个SO post),状态会随着每一个新的输入而改变。或者如果你玩电子游戏,会有大量的状态变量,从所有角色的位置开始,这些角色往往会不断移动。如果不跟踪不断变化的值,您怎么可能做任何有用的事情呢?
每次我发现一些讨论这个问题的东西,它都是用真正的技术函数语言写的,假设我没有浓厚的FP背景。有谁知道如何向那些对命令式编码有很好的、扎实的理解,但在函数方面完全是n00b的人解释这一点吗?
编辑:到目前为止,一堆回复似乎试图让我相信不可变值的优点。我懂你的意思。这很有道理。我不明白的是,在没有可变变量的情况下,如何跟踪必须不断变化的值。
下面是如何在没有可变状态的情况下编写代码:不是将变化状态放入可变变量中,而是将其放入函数的参数中。不写循环,而是写递归函数。比如这段命令式代码:
f_imperative(y) {
local x;
x := e;
while p(x, y) do
x := g(x, y)
return h(x, y)
}
变成这样的函数代码(类似scheme的语法):
(define (f-functional y)
(letrec (
(f-helper (lambda (x y)
(if (p x y)
(f-helper (g x y) y)
(h x y)))))
(f-helper e y)))
或者这个Haskellish代码
f_fun y = h x_final y
where x_initial = e
x_final = loop x_initial
loop x = if p x y then loop (g x y) else x
至于为什么函数式程序员喜欢这样做(你没有问),你的程序中无状态的部分越多,就有越多的方法可以在不中断的情况下将这些部分组合在一起。无状态范式的强大之处在于它本身不具有无状态性(或纯粹性),而在于它使您能够编写强大的、可重用的函数并将它们组合起来。
你可以在John Hughes的论文Why Functional Programming Matters中找到一个很好的教程,里面有很多例子。
让我们来回答更普遍的问题:
没有状态,你怎么做有用的事情?
你不。
寻找传统语言的替代品
我们必须首先认识到,一种制度不可能成为历史
敏感(允许执行一个程序来影响
一个后续的行为),除非系统已经
某种状态(第一个程序可以改变这种状态)
而第二个可以访问)。因此,历史敏感
计算系统的模型必须具有状态转换
语义学,至少在这个弱意义上。
约翰·巴克斯。
(由我强调)
重要的是巴克斯随后的观察:
但这不是
意味着每个计算都必须严重依赖于
复杂状态[…]
像Haskell或Clean这样的函数式语言允许您轻松地将这种观察付诸实践:大多数定义都是普通的函数,就像您在数学教育中看到的那样。这就留下了一小群“杂七杂八的人”来处理所有恼人的外部状态,例如:
与用户互动,
与远程服务通信,
处理模拟使用随机抽样,
打印出一个SVG文件(例如海报),
定期备份,
...两种语言都使用类型来区分普通和混杂。
有时,如果您试图实现的算法使用私有、局部可变状态实现,则效果最好。在这种情况下,你可以使用Haskell扩展来做到这一点,而不会让整个程序变得“内部杂乱”——详情请参阅John Launchbury和Simon Peyton Jones编写的State In Haskell。