我才刚刚开始学习函数式编程(FP)。我来自一个面向对象的世界,那里的一切都是对象,而且大多数都是可变的。我很难理解功能没有副作用的概念。
如果某些东西是不可变的,那么在FP中如何表示诸如Employee或Person之类的常见对象。
FP可以用于创建完整的企业应用程序吗?
我才刚刚开始学习函数式编程(FP)。我来自一个面向对象的世界,那里的一切都是对象,而且大多数都是可变的。我很难理解功能没有副作用的概念。
如果某些东西是不可变的,那么在FP中如何表示诸如Employee或Person之类的常见对象。
FP可以用于创建完整的企业应用程序吗?
Answers:
问题是不能在企业中使用FP吗?但是我们应该在企业中使用FP吗?
当然可以。您可以使用任何一种编程语言来开发任何一种应用程序,这就是为什么它们被称为“完成”。
现在,问题“应该在企业中使用它吗?” 这取决于您或您的雇主,FP在某些应用程序中可能真的有用,实际上,它已被大量使用:行业中的Haskell
现在,您可能会问:“为什么不使用更多?” 主要是因为其他命令式/ OO语言更常见,并且公司拒绝更改为更“奇特的”语言,因为它们已习惯于Java或C ++。
几年前,我开始学习FP语言(Haskell,Scala,Scheme),尽管我还不是专家,但我发现对于某些任务,除了C ++或Java之外,它们可以使我的工作效率更高。 。
IMO,FP语言的一些优势是:
到目前为止,我发现切换到FP范例非常令人兴奋,并且花费足够的时间也不会太困难。(但是我花了多少时间学习C或C ++?很多!)
因此,我认为从技术角度来看,使用功能性编程语言开发完整的企业应用程序非常有意义。
不幸的是,这种范例并不是主流:大多数公司倾向于只采用经过良好测试的技术,因此他们将远离FP,直到他们有足够的证据证明它确实有效,并且有足够的开发人员,工具,库和框架。因此,现在很难找到可以全职进行FP编程的工作。
如果越来越多地使用多核处理器将鼓励在FP语言上进行更多的投资,当前情况可能会改变,这对于编写并发软件来说似乎很强大。
另外,有一种趋势是将FP的某些功能引入主流的非功能性语言(如C#,C ++)中,以便程序员可以使用某些FP,而无需进行完整的范例转换。也许从现在开始的十年内,这些语言将涵盖足够的FP功能,从而使转换为纯功能语言变得容易得多。
我认为这不一定是最好的主意。但这取决于特定应用程序的性质。
我相信埃里克·埃文斯(Eric Evans)在他的著作《域驱动设计》中所描述的理念非常坚信,您应该制作一个可以代表当前问题的域模型,以帮助您解决问题。埃文斯(Evans)建议找到一种可以解决特定问题的编程语言,例如,他提到Fortran是解决数学性质问题的一种方式。甚至针对眼前的问题创建专门的领域特定语言。
成功创建良好的域模型后,您将发现表示代码最终只是域层顶部的薄壳。
现在,与企业应用程序有关的事情是,这种类型的应用程序(如果您可以概括企业应用程序)通常涉及修改具有重要身份的实体的状态,并将修改后的实体保存在数据库中。恕我直言,通过使用面向对象的模型比功能模型可以更好地解决这种非常普遍的问题。
这并不意味着企业应用程序的某些领域无法通过功能范式更好地解决。例如,银行应用程序的风险分析模块或运输应用程序中的路线计划模块。也许某些企业应用程序可以完全使用功能范例来实现。
但是总的来说,我认为面向对象的范例可以为大多数企业应用程序创建更有用的域模型。
编辑
由于一些投票,我的注意力集中在了这个答案上-自从我写它以来,我已经学到了很多有关FP的知识-而且我不确定自己是否会再同意我的答案。一些功能语言可以很好地描述用例。但是您需要学习完全不同的思维方式。
是的,FP可以用于企业应用程序。Clojure是成功在企业中使用的FP语言的一个示例:http : //cognitect.com/clojure#successstories
在FP中,表示状态可能是一个挑战,而更改范式以适应FP可能会有些许扭曲。一些FP语言完全禁止副作用和可变状态。Clojure允许两者,但不鼓励或隔离这些范式。
简而言之,状态表示可能与OO非常相似。状态修改是非常不同的。因此,例如,在FP状态下,可以由列表和地图表示。员工列表可能如下所示:
[[name: "James Brown" address: "Barnwell, SC"]
[name: "Elvis Presley" address: "Tupelo, MS"]]
我知道有两种方法可以处理FP中的状态修改。一类是函数式反应式编程。在此范例中,所有状态仅在最高级别上进行处理……例如,应用程序的HTML视图在视图中具有状态(例如人的姓名,地址等)。现在,当您单击“更新名称”时,将调用一个函数来处理有关名称更新的所有事情,除了实际更改名称外。这听起来可能很奇怪...但是请忍受我。然后,该更改的名称将由该函数返回,并且视图(或永久数据存储区等)将显示新名称。或者,将返回具有更新名称的全新结构。那功能是做什么的呢?验证名称并返回新名称(如果有效),否则返回错误,以及可能跟随的新视图或导航链接。对于比名称更复杂的事情,它可能会做更多的事情。
因此,对于FRP,函数返回的对象是新状态,可以直接提供给视图或任何高级视图。在某些情况下,FRP会将整个状态传递给函数,然后将整个状态返回。
使用这种范例,容器或框架需要处理显示,数据库的更新,或者需要从新状态进行更新的任何其他内容。因此,您可以想象一个在屏幕上绘制应用程序的框架。当用户单击时,将调用一些函数并返回新状态。然后,框架通过重绘所有内容或智能重绘显示的各个部分来更新屏幕。参见http://blog.getprismatic.com/om-sweet-om-high-functional-frontend-engineering-with-clojurescript-and-react/
Clojure使用了我遇到的第二个范例,即隔离状态更改,但不一定将其限制在最高级别。使用Clojure,所有可变状态都必须由原子,代理或引用“保留”(除非您将Java对象用于状态)。这种工作方式是原子/代理/引用持有或指向或引用的对象(无论如何调用它)是不可变的,但是原子/代理/引用可以更改以指向新对象。在这种情况下,您可以对atom / agent / ref使用特殊的方法,例如“在此更新对象,然后将atom / agent / ref重新分配给新对象”。
您可能会问为什么有好处?因为这些Clojure构造所引用的不可变对象可能会传递给执行某项功能的函数,并且在该函数运行时,保证了对该对象的引用不会更改。也就是说,没有将atom / agent / ref传递给函数,而是传递了它们所指向的不可变对象。原子,代理和引用具有特殊的属性,这些属性以安全且属于语言一部分的方式处理更新和并发。参见http://clojure.org/state
我希望这有帮助。我建议阅读更多有关Clojure状态和FRP的信息,以更好地了解FP中员工和人员的代表方式。不过,实际的表示方式将类似于面向对象的编程……可变性实际上是不同的。