|
1
177
Functional Programming in a Nutshell . 无状态编程有很多优点,尤其是 显著地 多线程和并发代码。坦率地说,可变状态是多线程代码的敌人。如果默认情况下值是不可变的,程序员就不需要担心一个线程在两个线程之间改变共享状态的值,因此它消除了与竞争条件相关的一整类多线程错误。由于没有竞争条件,也没有理由使用锁,因此不变性也消除了与死锁相关的另一类bug。 这就是函数式编程重要的原因,也可能是跳上函数式编程训练的最佳原因。还有很多其他好处,包括简化调试(即函数是纯的,不会在应用程序的其他部分改变状态),更简洁、更具表现力的代码,与严重依赖设计模式的语言相比,样板代码更少,编译器可以更积极地优化代码。 |
|
|
2
48
程序中无状态的部分越多, 有更多的方法可以把碎片拼凑在一起,而不会有任何破损 无国籍范式的力量不在于无国籍(或纯洁) 可重复使用的 你可以在约翰·休斯的论文中找到一个很好的教程,里面有很多例子 Why Functional Programming Matters (PDF)。 你会的 大量 更高效,特别是如果你选择一种也有代数数据类型和模式匹配的函数式语言(Caml、SML、Haskell)。 |
|
|
3
20
许多其他答案都集中在函数式编程的性能(并行性)方面,我认为这非常重要。然而,你确实特别询问了生产力,比如,在函数式范式中,你能比在命令式范式中更快地编写同样的东西吗。 我实际上发现(根据个人经验)用F#编程更符合我的想法,所以更容易。我认为这是最大的区别。我用F#和C#都编程过,在F#中“对抗语言”的次数要少得多,这是我所喜欢的。你不必考虑F#中的细节。以下是我发现自己真正喜欢的一些例子。
同样在F#中,不是编写循环,而是调用函数。这是一个微妙的变化,但意义重大,因为你不必再考虑循环构造了。例如,这里有一段代码,它将遍历并匹配一些东西(我不记得是什么,它来自一个欧拉谜题项目):
我意识到,在C#中先做一个过滤器,然后再做一个映射(这是每个元素的转换)会很简单,但你必须从较低的层次思考。特别是,你必须自己编写循环,并有自己的显式if语句,以及诸如此类的东西。自从学习F#以来,我意识到我发现用函数式编码更容易,如果你想过滤,你可以编写“过滤器”,如果你想要映射,你可以写“映射”,而不是实现每个细节。 我也喜欢|>运算符,我认为它将F#与ocaml以及可能的其他函数式语言分开。这是管道运算符,它允许您将一个表达式的输出“管道”到另一个表达式。它使代码更符合我的想法。就像上面的代码片段一样,也就是说,“取因子序列,过滤它,然后映射它。”这是一种非常高层次的思考,这在命令式编程语言中是不可能的,因为你忙于编写循环和if语句。每当我学习另一种语言时,这是我最想念的一件事。
|
|
|
4
15
考虑一下你花了很长时间调试的所有困难的bug。 现在,这些错误中有多少是由于程序的两个独立组件之间的“意外交互”造成的?(几乎所有线程错误都有这种形式:涉及写入共享数据的竞争、死锁……此外,还经常发现对全局状态或读/写注册表/环境有一些意外影响的库等。) 一、 假设至少三分之一的“硬bug”属于这一类。 现在,如果你切换到无状态/不可变/纯编程,所有这些错误都会消失。相反,你面临着一些新的挑战(例如,当你 做
|
|
5
8
无状态函数的一个优点是,它们允许预先计算或缓存函数的返回值。甚至一些C编译器也允许您显式地将函数标记为无状态,以提高它们的可优化性。正如许多其他人所指出的那样,无状态函数更容易并行化。 但效率并不是唯一的问题。纯函数更容易测试和调试,因为任何影响它的东西都是明确声明的。当用函数式语言编程时,人们习惯于尽可能少地使函数“脏”(用I/O等)。以这种方式分离出有状态的东西是设计程序的好方法,即使是在非函数式语言中也是如此。 函数式语言可能需要一段时间才能“理解”,而且很难向没有经历过这个过程的人解释。但大多数坚持了足够长时间的人最终意识到,即使他们最终不太使用函数式语言,这种大惊小怪也是值得的。 |
|
|
6
7
|
|
|
7
6
当你开始有更高的流量时,无状态的web应用程序是必不可少的。
负载均衡器通常具有“粘性会话”的能力,负载均衡器知道将用户请求发送到哪个服务器。但这并不理想,例如,这意味着每次重新启动web应用程序时,所有连接的用户都会失去会话。 更好的方法是将会话存储在web服务器后面的某种数据存储中,现在有很多很棒的nosql产品可用于此(redis、mongo、elasticsearch、memcached)。这样,web服务器是无状态的,但您仍然有状态服务器端,可以通过选择正确的数据存储设置来管理此状态的可用性。这些数据存储通常具有很大的冗余,因此几乎总是可以在不影响用户的情况下对web应用程序甚至数据存储进行更改。 |
|
|
8
5
对象
功能的
由于函数没有状态,并且输入的数据更明确,因此当您试图找出测试可能失败的原因时,需要关注的事情更少。关于我们必须做的柜台测试
前两行都有助于
相比之下,当你用函数式语言编写项目时,它会促使你保持花哨的算法依赖于流入和流出特定函数的数据,而不是依赖于系统的状态。 另一种看待它的方式是说明在每种范式中测试系统的心态。
对于面向对象编程:在对对象的状态执行Y和Z操作后,确保对象A的方法在给定输入参数X的情况下正常工作。在对对象的状态执行W和Y操作后,确保对象B的方法在给定输入参数X的情况下正常工作。 |
|
|
9
2
无状态编程的优点与无跳转编程的优点相吻合,只是更为明显。 尽管许多函数式编程的描述都强调缺乏变异,但缺乏变异也与缺乏无条件控制传输(如循环)密不可分。在函数式编程语言中,递归,特别是尾部递归,取代了循环。递归消除了无条件控制结构 和
然而,Dijkstra的观察仍然适用于避免 首选 ,因为这样的陈述 当 , 如果 什么都只是装点门面 首选 首选 给套笼头 首选 仍然存在所有相同的问题。
例如,为了说服自己递归函数是正确的,我们可以验证它的基本情况,然后理解和检验它的归纳假设。 首选 如果 , 当 以及其他结构。 然而,相比之下,在函数式程序中,没有任何变量的先验值可供推理;那类问题都解决了。 |
|
|
Emanuel Pinho · 无不变目标push的角度变化检测策略 8 年前 |
|
|
MingtyeP · 如何使用不可变js取消移动列表中的每个元素? 8 年前 |
|
|
Brannon · 让赋值运算符在申报时工作 8 年前 |
|
|
Javallion · JAVA中的不可变对象初始化 8 年前 |
|
|
Ankush Pandit · 字符串与字符串数组元素之间的比较 8 年前 |
|
|
plamkata__ · Swift到Kotlin,管理不可变列表 8 年前 |