可以使用函数式编程来开发完整的企业应用程序吗?


19

我才刚刚开始学习函数式编程(FP)。我来自一个面向对象的世界,那里的一切都是对象,而且大多数都是可变的。我很难理解功能没有副作用的概念。

如果某些东西是不可变的,那么在FP中如何表示诸如Employee或Person之类的常见对象。

FP可以用于创建完整的企业应用程序吗?


5
为什么员工代表必须是可变的?它可能具有状态,但这完全是另一个问题。

1
可变数据用于表示事物。相比之下,不可变数据在特定时间点具有某种价值(尽管这不是唯一的用例)。如果每个人都有一个错误,即您有两个表示相同事物的可变对象,那么您就会知道使用对象表示事物可能会崩溃的情况。
dan_waterworth 2012年

2
函数式编程产生副作用,否则您将永远无法打印任何内容。

1
@ThorbjørnRavn Andersen:在命令式(面向对象的过程式)编程中,您会使用副作用与外部世界(IO)进行通信以及计算程序中的数据转换。在FP中,您清楚地将两个世界分开了:仅对IO使用副作用(没有IO的程序通常是无用的),但是您使用纯函数来计算内部数据转换。副作用是无法完全避免的,但是由于它们不是局部的,因此更难以推理,因此最好限制使用。
乔治

诸如“人”对象之类的东西不需要是可变的。而是创建一个几乎相同(但略有不同)的全新“人员”对象。您将在某处引用“人”对象,并将其更改为引用新副本而不是旧副本。当然,该引用可能在某种集合中,因此请创建几乎相同的集合副本。必须在某处引用该集合,以便您可以将旧集合替换为新集合!
布伦丹

Answers:


17

问题是不能在企业中使用FP吗?但是我们应该在企业中使用FP吗?

当然可以。您可以使用任何一种编程语言来开发任何一种应用程序,这就是为什么它们被称为“完成”。

现在,问题“应该在企业中使用它吗?” 这取决于您或您的雇主,FP在某些应用程序中可能真的有用,实际上,它已被大量使用:行业中的Haskell

现在,您可能会问:“为什么不使用更多?” 主要是因为其他命令式/ OO语言更常见,并且公司拒绝更改为更“奇特的”语言,因为它们已习惯于Java或C ++。


7
You can develop any kind of application with any kind of programming language那是一个非常微弱的论据,当心图灵沥青 ……
yannis

5
@YannisRizos我认为他是为了提供一个针对性的答案,而不是探索问题的所有切线。
约翰尼·

2
@YannisRizos可能!=希望

1
有时候在我看来,对于某些企业解决方案来说,语言甚至不应该是图灵完整的……
shabunc 2012年

2
我认为这不取决于您的雇主,涉及语言时,应由工程师自己来推动我们从技术角度来看最好的东西。
shmish111

11

几年前,我开始学习FP语言(Haskell,Scala,Scheme),尽管我还不是专家,但我发现对于某些任务,除了C ++或Java之外,它们可以使我的工作效率更高。 。

IMO,FP语言的一些优势是:

  • 它们往往非常简洁,但是保留了清晰的语义。
  • 您可以使用声明式样式,而无需过多考虑实现细节。
  • 诸如Haskell的丰富类型系统可以在编译时很早地捕获许多逻辑错误。据我所知(实际上不是很多),SML和Ocaml具有类似的优势。

到目前为止,我发现切换到FP范例非常令人兴奋,并且花费足够的时间也不会太困难。(但是我花了多少时间学习C或C ++?很多!)

因此,我认为从技术角度来看,使用功能性编程语言开发完整的企业应用程序非常有意义。

不幸的是,这种范例并不是主流:大多数公司倾向于只采用经过良好测试的技术,因此他们将远离FP,直到他们有足够的证据证明它确实有效,并且有足够的开发人员,工具,库和框架。因此,现在很难找到可以全职进行FP编程的工作。

如果越来越多地使用多核处理器将鼓励在FP语言上进行更多的投资,当前情况可能会改变,这对于编写并发软件来说似乎很强大。

另外,有一种趋势是将FP的某些功能引入主流的非功能性语言(如C#,C ++)中,以便程序员可以使用某些FP,而无需进行完整的范例转换。也许从现在开始的十年内,这些语言将涵盖足够的FP功能,从而使转换为纯功能语言变得容易得多。


10

我认为这不一定是最好的主意。但这取决于特定应用程序的性质。

我相信埃里克·埃文斯(Eric Evans)在他的著作《域驱动设计》中所描述的理念非常坚信,您应该制作一个可以代表当前问题的域模型,以帮助您解决问题。埃文斯(Evans)建议找到一种可以解决特定问题的编程语言,例如,他提到Fortran是解决数学性质问题的一种方式。甚至针对眼前的问题创建专门的领域特定语言。

成功创建良好的域模型后,您将发现表示代码最终只是域层顶部的薄壳。

现在,与企业应用程序有关的事情是,这种类型的应用程序(如果您可以概括企业应用程序)通常涉及修改具有重要身份的实体的状态,并将修改后的实体保存在数据库中。恕我直言,通过使用面向对象的模型比功能模型可以更好地解决这种非常普遍的问题。

这并不意味着企业应用程序的某些领域无法通过功能范式更好地解决。例如,银行应用程序的风险分析模块或运输应用程序中的路线计划模块。也许某些企业应用程序可以完全使用功能范例来实现。

但是总的来说,我认为面向对象的范例可以为大多数企业应用程序创建更有用的域模型。

编辑

由于一些投票,我的注意力集中在了这个答案上-自从我写它以来,我已经学到了很多有关FP的知识-而且我不确定自己是否会再同意我的答案。一些功能语言可以很好地描述用例。但是您需要学习完全不同的思维方式。


2
+1:很好,很刺激的答案。由于我对FP的了解有限,所以我不确定这是否正确,但是我认为可以使用monad或唯一类型(在Clean中)对持久对象进行建模:这样,值可以获取身份,并在程序中传递并通过不同的功能进行转换。但是,我确实需要FP专家的意见来对此进行支持。
乔治

3

是的,它可以。Google了一下,您会发现用纯功能语言编码的真实软件。

至于您对业务对象的问题,我想您的实际问题在于不变性。在这种情况下,请考虑如果您使用命令式语言,则每次对其进行突变时都将返回一个新的“人员”。

注意,该技术也可以使用命令式语言来实现!


3

像面向对象编程(OOP)之类的函数编程(FP)是范例。它们代表解决编程问题的不同模式或方法。这些不同的方法不会消除产生可伸缩,可维护和可扩展软件的能力。这并不是说这些方法对于所有问题类型都是等效的。他们不是。某些问题会使自己更好(或更糟)地适应特定的范例,例如,对于具有依赖于操作的副作用序列的程序,FP并不是我的首选。但是,此类程序可以并且已经编写,并且编写得很好。


3

是的,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中员工和人员的代表方式。不过,实际的表示方式将类似于面向对象的编程……可变性实际上是不同的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.