為什麼這兩年函數式編程又火起來了呢?

函數式和過程式之間的Holy War在上個世紀就以過程式編程的全面勝出告終,函數式編程除了在學術界和人智領域外,幾乎無人問津。到21世紀初,MIT都不再用Scheme作為編程入門課,轉而使用Python。但是近幾年函數式編程為什麼又火了起來呢?C++11、Java8都對函數式編程提供專門語法支持,而Clojure, scala等新一代函數式語言也越來越多的用於Web開發。為什麼函數式編程死灰復燃了呢?有什麼新的應用需求促使開發者轉向函數式編程?


TLDR:這只是你的錯覺。

函數式編程一直都是慢慢的攻城掠地 。無論是從Search Trend,從學術界,從主流語言應用程度,都沒有『突然之間就火起來』。突然火起來的,是最近人人皆知的深度學習(我會用深度學習做對比組,指出真正火起來是像什麼樣的),不是函數式編程。

0:Search Trend

四圖流。由於Haskell把Scheme的Search Trend壓扁了(而Scala又壓HS),分開放。

有沒有急速上升?沒看出來。

這才叫急速上升嘛。

1:學術界研究

我會儘力給出跟FP有關的每十年的大發展。

192x: Combinatory logic

193x: Untyped Lambda Calculus

194x: Simply Typed Lambda Calculus

195x: Lisp

196x: APL, Denotational Semantic

197x: Intuitionistic Type Theory, ML

198x: Coq

199x: Haskell, Monad

200x: Hott? (現在說這些實在太早)

201x: ? (馬後炮很容易,現在讓我評選這個有點難)

對比,神經網路:由於我對早期發展沒理解,我就不放同樣的對比了。不過IMO,基礎發展也挺平緩的-這樣我們能看另一組數據:

terryum/awesome-deep-learning-papers

songrotek/Deep-Learning-Papers-Reading-Roadmap

這是Deep Learning的兩組數據,可以自己看下有多少是2016

caiorss/Functional-Programming

由於數據量實在太小,放上PLT的:

PLT by steshaw

也有不少Recent Work,但是你找不到DL內邊一樣的「2016大爆發」。

當然,這些數據很仁者見仁,可以很容易Engineer出想要的結論,所以我鼓勵你去自己寫下認為FP/ANN中很重要的東西/著名的書,然後對比下時間。

2:主流語言應用程度

這是TIOBE前20。

題主所說的C++Java,的確是近10年加入Lambda的。

但是,

0:在C++ Java中都是語法糖等級的東西,換言之不加入一樣也有高階函數。

1:Python, C#, Perl, JS, VB, 都是2010前加入Lambda的(Dart, Swift的確有2010後Lambda,不過他們倆就是2010後出的語言)

2:如果說其他的,C#, Python的List Comprehension也是2010前的,Java Generic則是1998由Philip Walder(Haskell界大佬), Martin Odersky(Scala界大佬)搞出來的

3:如果要說更遠的影響力,Smalltalk都被Lisp嚴重影響,然後Smalltalk再影響現在一大推OO語言。

換句話說,FP一直都有影響各種各樣的語言,不是近期才開始的。

對比:我們看下各種主流深度學習庫

aymericdamien/TopDeepLearning

裡面看下,有多少2010前的呢?

現在回到題主的問題

函數式和過程式之間的Holy War在上個世紀就以過程式編程的全面勝出告終

在這裡我提出一個猜想:一個編程範式從有 一群人 一起 一個 語言,到這個編程範式被工業應用,要20年左右。

過程式:Algol 58 Algol 60

工業應用:UnixC 80年代擴散出來,並且在7080年代過程式一直有爭議:

https://dspace.mit.edu/bitstream/handle/1721.1/5753/AIM-443.pdf

過程調用很貴,不如goto

http://web.mit.edu/humor/Computers/real.programmers

過程式是什麼鬼,數據結構又是什麼鬼,跟機器一點都不接近,又有一股學術界的臭味,我呸

(大家快take note,以後遇「函數式編程學術范,接近機器的C才是最好的」,就知道拿什麼東西壓他們了)

OOP:

Smalltalk,1972,或者Simula,1967(不過沒有一群人,不算)

Java,1995出來,Design Pattern書,1994,C++的確更早,1985就是Commercial Product,估計後幾年就有工業應用,不過C++搭了C的順風車,也有很多OO無關的東西,算半個outlier

而跟過程式被吐槽很學術很難懂一樣,OO也這樣被吐槽了(C++他爹是PHD)-這簡直是毅種循環,新的編程範式都是我不懂的玄學,舊的編程範式則是再正常不過的東西了(儘管誕生的時候一樣被看成玄學)

http://www.stroustrup.com/hopl-almost-final.pdf

函數式編程:Miranda 1985,不過是閉源商業化的,SML HS都是1990,ML/Scheme的確比較早,不過早期IMO(沒找到數據)都沒很多人。

這樣看來,2010左右主流PL融入函數式編程特性/函數式編程變主流只是很正常的歷史進程。

到21世紀初,MIT都不再用Scheme作為編程入門課

是他們倆教了20年教不動了= =

我們從另一個角度想,教很多FP/Intro是FP的有CMU, Texas Austin, University of Pennsylvania, University of Edinburgh, Imperial College,MIT一個Intro掉了,屬於來來去去,正常不過了

C++11、Java8都對函數式編程提供專門語法支持

上面已經論述過了。


很贊同狗大說的,根本的原因是摩爾定律不適用。cpu的如果不搞出什麼量子的玩意,基本上也就是堆核心,並行程序會大大提升效率,但是程序的穩定正確運行又是一問題,oo對這個的處理就顯得有些棘手,比如說java,各種鎖,各種同步。

下面引用下 什麼是函數式編程思維? - 用心閣的回答 - 知乎 中的片段

函數式編程的好處

由於命令式編程語言也可以通過類似函數指針的方式來實現高階函數,函數式的最主要的好處主要是不可變性帶來的。沒有可變的狀態,函數就是引用透明(Referential transparency)的和沒有副作用(No Side Effect

一個好處是,函數即不依賴外部的狀態也不修改外部的狀態,函數調用的結果不依賴調用的時間和位置,這樣寫的代碼容易進行推理,不容易出錯。這使得單元測試和調試都更容易。

不變性帶來的另一個好處是:由於(多個線程之間)不共享狀態,不會造成資源爭用(Race condition),也就不需要用來保護可變狀態,也就不會出現死鎖,這樣可以更好地並發起來,尤其是在對稱多處理器(SMP)架構下能夠更好地利用多個處理器(核)提供的並行處理能力。

出於對效率,安全,穩定以及運行速度的追求,在多核心cpu上並行的搞起來編程會火,將來也是大勢所在(個人想法,勿噴)。

然後說java也在努力的改革,進步,在像函數式「進化」,比如說java8提供的Stream流,lambda,努力將函數(方法)提升為一等公民,Stream中的透明化,無態化都流露著函數式的思想。雖然java的fp現在可能走得是oop的極端表現形式,但是也從另一個側面表達了fp的優點和將來大勢所在。


不就是寫起來方便大家就用了唄。

用C語言的時候,不是一樣函數指針漫天飛,啥時候大家不用函數式編程了。


因為內存夠了


根本的原因是摩爾定律不適用。

cpu的性能提升將體現在核數增加,這樣並行的程序運行速度會越來越快。並行的程序的寫法就是找出不能並行的地方,其他地方都盡量並行。

如果要這樣寫,最需要避免的事情就是賦值。函數式編程的本質就是,規避掉「賦值」。


編程從一開始就是函數式的,後來給smalltalk插了一腳,然後面向對象死灰復燃,才是正確的描述。


因為懂編程的人越來越多了,另外,其實也不是很火。


因為GUI已經不是熱點了。


多核時代來了。函數式編程好寫並發


因為CPU的增長已經不符合摩爾定律,只能通過增加cpu的數量來提升性能,而函數式語言對並髮式編程的支持更好,面向對象語言因為數據和操作的綁定導致鎖定資源花費的代價太大。


因為函數式編程才是正確的姿勢

Java 那種東西都是異端中的異端


函數式和過程式的表達能力本質上是等價的,那麼它們的根本區別概括地來說就是,過程式對運行時更友好,函數式對開發時更友好。

那麼,函數式的重新流行,就跟程序員地位提高、copyleft的興起、快速迭代式的流行等歷史大潮有著緊密的關係,而不是簡單地從計算機性能提高就能導出這一結論。

函數式編程的確適於並發,然而那只是問題的一部分。對於一個「良好編寫」的程序,原來函數式比過程式慢五十倍,現在只慢五倍,然而如果程序員基本不要錢,你們老闆還是會繼續要你們用彙編。


前面有人說過了,fp更適合併發,熟練之後寫程序也更簡潔,但fp天生對gui不友好,這塊和oo差太多。性能也有瓶頸,所以大部分語言只是支持部分fp特性,而不是純fp。


這個是從2000年前後開始興起的「設計模式」思潮的自然延續。我印象中過去十幾年的「設計模式」思潮的關注點大概包括(時間順序不嚴格):

  1. GoF Patterns
  2. IoC / Container, Application Server (e.g. EJB)
  3. UML / MDA
  4. ORM
  5. AOP / Meta-Programming
  6. SOA
  7. Concurrency Facility: Fiber, Green-thread / Message Passing Patterns
  8. Async Facility
  9. NoSQL
  10. Functional Programming / Map-Reduce


別拿Lisp scheme racket haskell erlang 說事,這幾個大神們自個都還在撕逼呢(都十幾年了)

簡單來說就是多核心CPU的low逼化使得資本家對平行運算的需求急劇上升。現有的大部分OOP開發的系統(C++和Java為主)在狀態封裝的處理上非常差,因為FP的一些觀點和語法處理可以避免程序員再犯類似的錯誤。

可是這些所謂問題,其實Smalltalk早就解決了(pre 1995),誰叫C++/Java這種東西成了主流語言呢...

誰叫課本只教PIE,沒說清楚State 和 message 呢


因為計算機性能跟得上了啊。C 規範為了省一個 pass 都要規定 main 之前就算不定義也得把函數簽名聲明出來,那時候誰敢像現在的 Haskell 這樣用內存啊。


眼睜睜看著python越來越流行,表示並沒有...


因為免費的午餐已經結束了,其實早就結束了。

The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software


除了非同步編程之外,

資料庫做orm之後的查詢,傳入一個閉包來描述我要什麼條件的對象,顯然比傳入一個條件語句要人性化。


長期習慣了命令式編程後,加入一些函數式編程的方法,確實可以讓程序更簡潔優雅。

我覺得類似scala的流行是編程思想的一種進化,將多個範式的優點結合起來,各取所長,它們並不是完全相互排斥的。,就是CISC/RISC融合一樣。以前的命令式語言沒做到這一點,現代語言越來越強大了。

對並發的日漸重視應該也是一個原因吧。


推薦閱讀:

TAG:編程語言 | Scala | 函數式編程 | Clojure |