为什么函数式语言支持不可变类型很重要?

Why its important for a functional language to support immutable types?

正如所讨论的 我们现在知道判断语言是否具有功能性的特征是什么。但是,不变性在哪里适合这种情况?

这是一个快速的心理练习,使用伪代码:

1) x = 5;
2) x = x + 1;
3) print x; // prints "6"
4) x = x
// THEREFORE 5 = 6

对吧?我们从第 1 行知道 x 是 5,从第 3 行知道 x 是 6,所以如果 x = x,那么 5 必须等于 6。

这里的笑话是我们将命令式、面向命令的思维与数学、函数式思维混合在一起。在命令式风格中,x 是一个变量,这意味着我们假设它的值可能随时间变化。但是当我们做数学时,我们做了一个不同的假设:我们假设 "x" 是一个特定的值,这意味着一旦我们知道 "x" 的值,我们就可以在 "x" 出现的任何地方替换该值.该假设是能够求解方程的全部基础。显然,如果 "x" 的值从我们下面改变,就像上面的心理练习的第 2 行那样,那么所有的赌注都没有了。第 2 行不是有效的数学,因为没有任何值可以使语句 x = x + 1 在数学上为真。 (至少就我所学的高中数学而言!)

另一种看待它的方式是说命令式编程混合了值、函数和状态,这让人很难推理。因为 "x" 的值可能会有所不同,具体取决于您查看它的时间,所以您无法仅通过查看您的代码就可以轻易地知道它会对您的代码运行方式产生什么影响。您必须 "play compiler" 并在头脑中跟踪所有变量以及它们如何随时间变化,这很快就会变得难以管理。状态是计算机编程中附带复杂性的第一大来源。

函数式编程通过将状态与函数分离来简化事情。在像 f(x) = (x * x) 这样的数学函数中,"x" 的值不会随时间变化。这是对 "x" 和 "f(x)" 之间关系的纯粹描述,无论您先看 "x" 还是先看 "f(x)",这种关系总是正确的。没有国家参与。您正在描述值之间的关系,与时间无关,也没有任何状态。而且因为您不必担心状态从您的下方发生变化,您可以更轻松、更安全地推断输入和输出之间的关系。

不可变变量通过从代码中删除时间和可变性元素来模拟这种无状态的数学推理。你仍然需要在某个时候改变你的状态,但你可以推迟到以后,并且只有在你的纯函数计算出正确的值来存储之后才更新状态。通过将状态管理与您的纯函数分离,您可以使编码更简单、更容易推理并且通常更可靠。此外,测试纯函数要容易得多,因为不需要模拟或额外设置或其他状态模拟先决条件。

所有这一切真正酷的是,即使 "x" 是比简单数字更复杂的东西,同样适用。您可以编写纯函数,其参数是数组、记录、客户对象等,同样的原则仍然适用。通过保持你的函数纯净和你的值不可变,你正在编写描述函数参数和函数输出之间关系的代码,而没有时间和状态的附带复杂性。那是巨大的。