为什么目前对函数式编程充满热情?[关闭]


50

最近,对于Scala,Clojure和F#,我已经听到了很多有关函数式编程语言的热情。我最近开始学习Haskell,以学习FP范例。

我喜欢它,它真的很有趣,并且适合我的数学背景。

但这真的有关系吗?显然,这并不是一个新主意。

这是我的问题:

  1. 是什么促成了最近FP的热情?是对OO仅仅是无聊,还是为了使FP比以前更需要而进行了一些更改?
  2. 这是否预示着FP的未来?还是像对象数据库这样的时尚?

换句话说,任何人都可以帮助我了解它的来历和去向吗?



13
不是重复的-这是在问人们为什么突然大惊小怪,因为这不是一个新主意(尽管这个问题要求更多的客观差异)。
彼得·布顿

2
人们最近对FP大惊小怪吗?给我的消息是,我认为某些团队一直在争论FP如何接管命令式编程世界,这种情况一直都是这样。
克里斯,2010年

1
我想我已经在StackOverflow上回答了这个问题
肯·布鲁姆

1
是的-我认为FP已经很旧了,我想当我1989年在哥伦比亚大学使用Scheme作为本科生时。我猜这是闪亮的新事物。
蒂姆(Tim)2010年

Answers:


33

导致“兴趣爆炸”的FP的主要创新之一是monads。

1992年1月,Philip Wadler撰写了一篇名为《函数式编程的本质》的论文,论文将monads引入函数式编程中,作为处理IO的一种方式。

纯的,惰性的,功能性编程语言的主要问题是处理IO的实用性。它是程序设计中“笨拙小队”的成员之一,因为“从实用的角度来看,懒惰和副作用是不兼容的。如果要使用惰性语言,它几乎必须是一种纯粹的功能性语言。如果要使用副作用,最好使用严格的语言。” 参考

在monads之前的IO问题是,对于实际上对任何事情都有用的程序,保持纯度是不可能的。所谓IO,是指处理状态变化的任何事物,包括从用户或环境获取输入和输出。在纯函数式编程中,所有内容都是不可变的,以实现惰性和纯净(无副作用)。

monads如何解决IO问题?好吧,无需过多讨论monad,他们基本上将“ World”(运行时环境)作为monad的输入,并产生一个新的“ World”作为输出,其结果是:IO a = World->(a,世界)。

因此,FP已进入越来越多的主流,因为最大的问题IO(及其他)已经解决。众所周知,已经集成到现有的OO语言中。例如,LINQ就是单子。

有关更多信息,建议阅读有关我的答案中引用的monad和论文。


非常有用,谢谢。我接受这个答案,不是因为它是正确的,而其他人是错误的(我已经提出了几个建议),而是因为我认为它值得得到可见的结果。
埃里克·威尔逊

不过,一个更相关的示例将是type IO a = UI -> (a, UI)一个绝妙的答案。
ChaosPandion 2010年

@Richard:“输入IO a = World->(a,World)”听起来好得难以置信(我以为我永远不会得到单子)。我猜您将LINQ比作monad,是因为当您将lambda传递给LINQ运算符时,lambda会“看到”其整个环境,对吗?
Stefan Monov 2010年

@Stefan:说lambda看到它的环境听起来有些准确,但是我对此并不百分百清楚,所以我会犹豫回答,直到我自己了解更多。但是,我可以100%肯定地说LINQ是monads,因为创建者在很多场合都这样说。SelectMany完全等同于Haskell中的Bind。如果您还没有读过《 Monads的奇迹》(blogs.msdn.com/b/wesdyer/archive/2008/01/11/…),我强烈推荐它……它将揭示LINQ是如何真正实现Monads的。干杯。
理查德·安东尼·海因

1
@Job,请参见上述评论中提到的blogs.msdn.com/b/wesdyer/archive/2008/01/11/…
理查德·安东尼·海因

30

对传统语言(如C,Java,C#,汇编器等)进行编程时的主要问题之一是,为了完成给定的任务,您必须采取一系列尴尬的步骤,因为您需要先准备所有依赖项,然后再准备。较早的依赖

例如:为了执行A,您必须有B和C,并且B取决于D和E,结果是

  • ð
  • Ë
  • C
  • 一种

因为您必须先准备好成分,然后才能使用它们。

函数式语言,尤其是惰性语言,使这一语言颠倒了。通过让A说它需要B和C,并让语言运行时弄清楚何时获取B和C(这又需要D和E),所有这些都在需要评估A时进行评估,因此您可以创建非常简洁的代码构建块,从而导致程序精简。惰性语言还允许使用无限列表,因为仅计算实际使用的元素,而无需在能够使用整个数据结构之前将其存储在内存中。

真正的妙招是,这种自动的“哦,我需要一个B和C”机制是可扩展的,因为对执行该评估的位置和时间没有任何限制(如在顺序程序中一样),因此可以在甚至在不同的处理器或计算机上。

就是功能语言之所以有趣的原因-因为“运行时做什么”机制由运行时系统接管,而不是程序员必须手动进行。这与从Java到C的自动垃圾回收一样重要,这是一个主要差异,这也是为什么用Java编写比C编写健壮的,可扩展的多线程软件要容易得多的主要原因之一。功能语言中的可扩展多线程软件...


3
当然,在1950年确实如此。
埃里克·威尔逊

1
@FarmBoy,不是真的,但是今天。

5
这与依赖注入有何不同?
Bill K

2
@Bill K,非常棒的观察-我自己没有建立这种联系。区别在于,至少在Java中,要急切地评估要注入的对象,而不是懒惰地评估要注入的对象。您不能注入无限列表。

1
@ThorbjørnRavn Andersen我不太确定我是否理解为什么无限列表会很有用,您实际上可以对(无限列表)类型的操作求和吗?似乎非常不可能。否则,这听起来像Java使用迭代器的方式,您只是以这样的方式对迭代器进行编码:仅在请求对象时实例化对象-并不是无限的,而是永无止境的(有很大的不同,是吗? )
Bill K

21

在80年代末/ 90年代初,计算机变得足够强大,可以用于Smalltalk风格的OOP。如今,计算机对于FP而言已经足够强大。FP是在更高层次上进行编程的,因此,尽管编程更愉快,但不是最有效的方法确实可以解决某个问题。但是计算机是如此之快,以至于您不在乎。

使用纯功能编程语言可以更轻松地进行多核编程,因为您必须隔离状态改变代码。

今天,编程语言的边界也变得模糊。如果您想使用另一种范例,则不必放弃一种范例。您可以使用大多数流行语言进行FP,因此入门门槛很低。


6
要添加一个答案,但是您在最后一句话中说了我的意思;随着一台机器中内核数量的增加,功能编程将变得越来越普遍。内在的缺乏状态使得在处理器之间机械地分割功能程序变得更加容易(这意味着,如果您有一个纯粹的功能程序,那么从理论上讲,编译器可以为您处理并行性,而您只需花费很少的精力就可以看到youtube.com/watch? v = NWSZ4c9yqW8,用于讨论数据并行性)。
Inaimathi 2010年

1
@Inaimathi同上。函数式编程具有很好的可扩展性,因此在多核体系结构上很有意义。
EricBoersma,2010年

请注意,我的第一条评论是在对答案进行编辑以包含其他声明之前写的。
Inaimathi 2010年

抱歉 我只是忘记了这一点。
LennyProgrammers 2010年

函数编译器不能像OOPS一样优化生成机器代码,这是否真的为人们所普遍接受?我想不出任何理论上的理由为什么这必须成立。而且我可以想到比OOPS更高级的优化方法。
杰里米

7

如今需要分布式计算。

FP使用功能作为没有状态的构建块,因此 ,使用相同参数调用n次的功能应始终返回相同的值,并且不会产生副作用。

因此,您可以将相同的功能发送到一堆机器上,以并行执行工作。

在OO范式中,这有点困难,因为构造块是对象,根据定义,它们几乎是有状态的。如果多次调用相同的方法,则在同步内部数据时必须小心,以避免数据损坏。尽管仍然可能,但是在某些必须分配计算的情况下,FP范例比OO更好。

FP(某种程度上是NoSQL)的出现是在数十万台并行计算机上实现惊人的计算结果的故事之后的,并且它是多么容易。

但这可能只是需要这种设置的应用程序的一种小众市场。对于许多其他应用程序/系统,过程和OO都可以正常工作。

因此,所有这些都将扩大我们的编程视野,并重新采用我们曾经认为不会超出学术界的这些概念。

几年前,我学会了用Lisp编程,那时,我什至不知道那是FP。到现在为止,我几乎已经忘记了有关它的所有内容,但是可以肯定地帮助我很容易地理解诸如递归的概念。


2
问题是询问类似于FP的语言的优势。您描述的内容也可以使用传统语言来完成。
Pacerier,2014年

6

我们正迈向一个时代,在这个时代,多核处理不仅仅是在科学实验室的后台或在专用硬件上完成的。现在可以通过商品处理器来完成。函数编程,至少是我接触过的大多数变体,通常都试图推动对无副作用,无状态计算单元的看法。这是多核工作的典型范例,因为不需要保持处理器之间的状态混合。

这只是原因之一,而函数式编程占据了上风。


5

我认为该问题的主要答案是“暴露”。

函数式编程并不是什么新鲜事物,大约12年前,我在大学里曾教过Haskell,并且喜欢它。但是在我的专业工作中很少使用这种语言。

最近,主流语言中已经有许多使用多范式方法的语言受到关注。F#,JavaScript是最好的例子。

特别是JavaScript,特别是与功能样式的框架语言(如jQueryPrototype)一起使用时,由于动态现代网站上的所有工作,JavaScript 已成为许多人的日常语言。这种对功能风格的了解使人们意识到了它所赋予的力量,尤其是当人们能够随意退回到命令式风格时。

一旦人们接触了它们,他们就会尝试功能语言的更为完善的变体,并开始将其用于日常任务。

随着F#在Visual Studio 2010中成为一门一流的语言,而jQuery(et al)变得如此重要,使用这些语言变得越来越现实,而不是仅仅使用晦涩难懂的程序或制作独立的程序。

请记住,代码必须是可维护的-一定数量的开发人员必须使用和支持语言,以使公司在使用它们时感到安全。


3

演讲中,安德斯·海斯伯格(Anders Hejlsberg)解释了他对该主题的看法。

[编辑]

抱歉,链接错误。现在它指向正确的位置。

一小时通话的一些要点的简短摘要:

功能语言比程序​​语言允许使用更具声明性的编程风格,因此用FL编写的程序通常更专注于what而不是how。由于FL具有优雅的数学结构,因此它们也更易于通过编译器进行优化和转换,这也使元编程和嵌入式DSL的构建变得容易。所有这些加在一起使功能性程序比程序性程序更简洁,更易于记录文档。

同样,面对不久的将来的多核时代,编程语言需要能够以不同的方式利用多线程/处理。单核计算机上的多线程实际上是一种时间共享机制,而系统的体系结构反映了这一点。manycore机器上的多线程将大不相同。函数语言特别适合于并行化,因为它们大多数情况下会避免状态,因此不必担心共享可变数据的完整性(因为往往没有共享可变数据)。


1
你能总结一下吗?

1
@Thorbjorn那让我想起了一个无法总结的人。(没有针对您,回答作者。)
Mark C 2010年

1
该链接甚至没有链接到正确的位置。
肯·布鲁姆

2

我认为这与功能编程范例和Web编程之间的紧密关联有关。

Ruby on Rails为整个功能编程方法带来了极大的缓解,因为它提供了快速访问功能性(heh heh)Web应用程序的途径。关于此,有一个有趣的讨论,一个特别的答案很突出:

函数式编程非常适合Web应用程序。该Web应用程序接收HTTP请求并产生HTML结果。这可以被认为是从请求到页面的功能。

与台式机应用程序相比,台式机应用程序通常需要长时间运行,有状态的UI和多个方向的数据流。这更适用于OO,它关注具有状态和消息传递的对象。

鉴于函数式编程已经存在了很长时间,我想知道为什么我没有看到很多招聘广告为Lisp开发人员开发未开发的Web项目。


我认为功能类比只是偶然地适用于Web,因为底层协议是无状态的。Web应用程序并不是真正的无状态的,这实际上是我们始终必须以某种方式解决HTTP的原因。
MladenJablanović10年

@Mladen Hmmm,您是否可能将客户端-服务器通信状态(HTTP)与应用程序状态(DAO等)合并?从此处引用Stefan Tilkov(codemonkeyism.com/stateless-applications-illusion)“在Web应用程序中,每个单独的请求都应包含足够的信息,以便可以独立于上一个请求是否发生而进行处理。持久的服务器端资源状态很好,客户端状态很好,瞬态通信(会话)状态不是因为它会破坏可伸缩性和可书签性。” 这是REST的基础。
加里·罗

1
您可能需要阅读paulgraham.com/avg.html,以更好地了解为什么没有太多招聘广告来寻找Lisp开发人员。

@ThorbjørnRavn Andersen好文章。激发我突破Lisp编辑器的风范。
加里·罗

1

函数编程给我带来了“ 哇,这是新的 ”的刺痛感,就像我几年前刚开始涉​​足对象时一样。

我意识到FP到目前为止并不是一个新概念,但是当它在90年代真正突破时,“每个人”突然从程序编程中退出时,OO也不是。这主要是由于Java和后来的C#的及时成功。

我想一旦下一批语言开始以相同的方式传播,FP最终会发生同样的事情。至少在某些方面,他们已经使用了Scala和F#之类的语言。


OO比FP还要年轻,但是它早已成为关注的焦点。我猜想括号会吓到很多人
哈维尔2010年

1

这是我的问题:1.是什么导致了最近的FP热情?是对OO仅仅是无聊,还是为了使FP比以前更需要而进行了一些更改?2.这是否预示着FP的未来?还是像对象数据库这样的时尚?

其他人给出了很好的技术理由。

我认为FP在普通开发人员和管理人员类型中获得青睐的主要原因是,它有望允许更好地使用多核CPU。从我读过的所有文章中,FP都允许更轻松(而不容易)的并行编程。

如果诺言是真实的并得以实现,那么将来的广泛使用将是。


那是一个很大的“如果”。COBOL是“英语”,这意味着任何人都可以编程。人工智能将使编程过时。OO将使编程像组装Tinkertoys一样简单。编码人员就像摇滚小伙子一样,总是在寻找“下一件大事”,然后是另一件……
Mike Dunlavey 2010年

0

我认为这是两种趋势的结合:

  1. 功能功能已添加到主流语言(例如C#)中。
  2. 正在创建新的功能语言。

第一种趋势可能有一个自然的限制,但我猜想,任何新语言都必须(至少作为一种选择)必须支持函数式编程,以便受到重视。


0

过去,人们是使用操作系统的本机API编写要在桌面上运行的程序的,而这些API(通常)是用C编写的,因此,如果您想为本机API编写程序,则通常用C编写了该程序。

我认为过去10年左右的新创新是要赶上各种API,尤其是对于平台API无关的Web开发之类的事情(因为构建网页基本上涉及字符串操作)。由于您没有直接使用Win32 API或POSIX API进行编码,因此人们可以自由地试用功能语言。


0

整洁又漂亮,使您的大脑发痒。没关系。

恕我直言,这也是经典的潮流。寻找问题的解决方案。

就像所有由工程师创立的初创公司眼花with乱的想法一样,它们虽然燃烧了一会儿,但是却被那些提供所需东西的公司悄然超越。

这是我希望看到的新想法,它是基于需求的编程,而不是基于漂亮思想的编程。也许这听起来很平凡,但我认为它实际上可以非常有创意,而且很漂亮。


-1

绝对是因为F#,尽管有时很难分辨是哪一个是原因,哪一个是结果。

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.