函數(shù)式編程很難啊掏,這正是你要學(xué)習(xí)它的原因


  英文原文Functional Programming Is Hard,That's Why It's Good
  很奇怪不是,很少有人每天都使用函數(shù)式編程語言拷恨。如果你用Scala, Haskell, Erlang,F#或某個Lisp方言來編程脖律,很可能沒有公司會花錢聘你。這個行業(yè)里的絕大部分人都是使用像Python, Ruby, Java或C#等面向?qū)ο蟮木幊陶Z言腕侄,它們用起來很順手小泉。不錯,你也許會偶然用到一兩個函數(shù)式語言特征冕杠,例如block微姊,但人們不會去做函數(shù)式編程。
  然而分预,很多年來兢交,我們一直被教導(dǎo)說函數(shù)式編程語言很好很棒。我仍然記得當(dāng)我第一次閱讀ESR的著名的關(guān)于學(xué)習(xí)Lisp語言的論文時的困惑笼痹。也許大多數(shù)的人對Paul Graham 的《Beating The Averages》這篇文章更加熟悉:

使用Lisp開發(fā)使我們的開發(fā)周期迭代的如此之快配喳,以至于有時當(dāng)競爭對手在新聞發(fā)布會上推出他們的新功能一兩天后,我們就能復(fù)制出同樣的功能凳干。當(dāng)報道產(chǎn)品發(fā)布的新聞記者打電話給我們時晴裹,我們的產(chǎn)品已經(jīng)擁有了同樣的功能特征。

那些皈依函數(shù)式編程的人中救赐,一直常見的考慮是:學(xué)習(xí)這種新的涧团、函數(shù)式的語言對你有好處;就像是某些人建議說每天30分鐘的健身房活動會讓你的身體健康一樣。但這也同時暗示了這樣做的難度和需要的付出泌绣。Lisp語言跟Haskell钮追、Ocaml和Scala語言不同,被認為是出了名的難學(xué)阿迈,可以說是臭名昭著元媚。文雅的人說這是Lisp語言的深度&廣度的體現(xiàn)。不文雅的人說這是意淫或玩弄學(xué)術(shù)或簡單的沒必要仿滔。我認為惠毁,它的難度跟你對它熟不熟悉有關(guān)乾蛤,而且锥债,這種難度是一種重要指標(biāo)顯示:學(xué)習(xí)這樣的一種語言會讓你編程更有效率昔善、能力更強歪架。
  它給你的初次印象不友善
  我7歲時就開始編程墓怀,在漫長無聊的郊區(qū)夏季里因妇,在我祖父的計算機上瞎搞一氣躺翻。我學(xué)了BASIC等舔,用它在屏幕上畫一個蹦跳的球牺荠。我學(xué)了Pascal翁巍,用它寫了一個能通過PC喇叭放音樂的程序。大概10歲時我學(xué)了C語言休雌,但遇到了一堵越不過去的墻灶壶,直到我上了高中。那就是:指針杈曲。即使不算這些該死的指針驰凛,我寫、讀担扑、學(xué)習(xí)恰响、練習(xí)中,同樣遭遇無數(shù)的失敗涌献。我把祖父的硬盤給毀掉了兩次(一次屬意外)胚宦,最后弄得不少次要自己重裝操作系統(tǒng)。我失敗燕垃,一遍遍的失敗枢劝。
  也許你也有跟我相似的故事,也許是完全不同的一個卜壕。但我想呈野,差不多所有學(xué)過編程的人都有過遇到困難的經(jīng)歷。我們在學(xué)了一些基本知識后印叁,必然會遇到一些公認的概念上的關(guān)口,比如指針。很多計算機科學(xué)教授會把指針描述為他們課程上的過濾網(wǎng)轮蜕。如果你想成為一名優(yōu)秀的程序員昨悼,你必須要能理解指針。很少人能輕松的掌握它們跃洛。大多數(shù)人率触,包括我,則需要不斷的練習(xí)和參考例子來理解什么是指針汇竭、為什么它們很重要葱蝗。
  這種艱難的努力過程不是偶然的,是一種幾乎普遍的現(xiàn)象细燎。指針是一種非常強大和基礎(chǔ)功能的概念两曼。學(xué)會它能讓你成為一名更好的程序員,能讓你的思考更加形象化玻驻。即使你使用的語言并不提供指針這樣的特征悼凑,但跟指針類似的數(shù)據(jù)結(jié)構(gòu)和概念卻隨處可見。
  新奇事物
  一旦你學(xué)會了幾種語言后璧瞬,所有的語言都開始看起來都很相似户辫。知道Python的人學(xué)習(xí)Ruby可能不會遇到太多的問題,知道Java的人學(xué)習(xí)C#會感到很熟悉嗤锉。不錯渔欢,也有意外的地方。Ruby愛好者在學(xué)習(xí)Python時會對它的comprehension感到吃驚瘟忱,Java用戶會對C#里的委托摸不著頭腦奥额。還是那句話,如果你只瞟一眼酷誓,它們都很相似披坏。我可以打保票的說,如果你還不曾有過這樣的認識盐数,一旦你學(xué)了一種Lisp語言棒拂,你會發(fā)現(xiàn)所有的Lisp變種都很相似。
  有人說玫氢,大部分人第一次使用Haskell或Ocaml時都完全的不知所措帚屉。見鬼了,在Haskell里漾峡,連分號都跟別人不一樣攻旦。這并不是語法的問題;Haskell和ML語言完全基于一種不同的概念生逸、一種新的語言范式牢屋。你需要用不同的方式開發(fā)應(yīng)用且预,不同的方式組織應(yīng)用,不同的方式擴展應(yīng)用烙无。
  很多這樣的新概念都具有不可思議的強大力量锋谐。Haskell里的Monads是跟指針一樣基礎(chǔ)且強大的概念(你很可能在不知道它叫什么的情況下就已經(jīng)使用過它們了)。所以截酷,跟學(xué)了Java后再學(xué)C#不一樣涮拗,有志向?qū)W習(xí)函數(shù)式語言的人需要往回走的更遠,去學(xué)習(xí)更加基礎(chǔ)的概念后才能接下去學(xué)習(xí)迂苛。就像是完全再學(xué)習(xí)一次指針三热。并且,就像是當(dāng)年我們剛開始學(xué)習(xí)編程一樣三幻,一些很大的概念看起來會讓人迷惑茫然就漾,讓人沮喪,直到你去攻克(以及失敗)它們赌髓。
  吃下你的藥丸从藤,找到你的藥劑師
  盡管不好學(xué),但我堅信锁蠕,學(xué)習(xí)這些函數(shù)式編程語言會在職業(yè)上對你有好處夷野。我相信有些人讀到這點時會眼睛翻起來向天看,很難想象出這些monoids或monad會對他們在使用Java或C#時有用處荣倾。對我而言悯搔,我已經(jīng)不驚奇于由于這樣的思維而阻止他們學(xué)習(xí)函數(shù)式語言的現(xiàn)象;他們需要學(xué)習(xí)一種跟指針和遞歸一樣基礎(chǔ)的新概念舌仍。他們需要有一種只有專業(yè)人員在完成清晰的商業(yè)目標(biāo)時才具有的耐心和斗志妒貌。很少人能在過了可塑的年齡后還受得了一次又一次的挫折,否則我們現(xiàn)在都早成專家了铸豁,不是嗎灌曙?
  還有更復(fù)雜的東西,有大量的語言和算法研究都是用函數(shù)式語言實施的(尤其是Haskell)节芥。你很容易會被這些不熟悉的概念例如分類學(xué)理論, half-finished abstractions头镊,一些失敗的研究弄的迷失方向。沒有一個清晰的指導(dǎo)(比如由一個實用主義的作者寫的一本好書)相艇,本來已經(jīng)很困難的學(xué)習(xí)任務(wù)變的更加可怕。
  這些疊加起來的復(fù)雜因素導(dǎo)致了不出意外的結(jié)果:很多人不情愿在函數(shù)式編程學(xué)習(xí)中投入時間坛芽。很容易理解這種不情愿留储,我干嘛不把花在學(xué)習(xí)這些東西的時間用在實現(xiàn)什么東西上呢?但這種思路也表明了你永遠不愿意在任何新技術(shù)上浪費時間(只用自己熟悉的)获讳。在一個像軟件技術(shù)這樣日新月異的產(chǎn)業(yè)里,我不認為這是正確的判斷赔嚎。
  眼見為實
  學(xué)習(xí)一種函數(shù)式編程語言最顯而易見的好處是尤误,你能學(xué)會這種類型語言中的函數(shù)式概念。它能幫助你的大腦结缚,讓它具有能非常清晰的思考和處理一些驚人的重大概念的能力。這并不是函數(shù)式編程具有魔法红竭;各種語言和范式的出現(xiàn)都是為了應(yīng)對某一特定類別的問題。函數(shù)式編程的殺手锏正是應(yīng)對了當(dāng)今世界上日益增長的并行性編程和元數(shù)據(jù)編程趨勢茵宪。
  例如,我們研究一個簡化的稀火、本地版本化的Google著名的MapReduce范例暖哨。用函數(shù)式方式描述這種范例是不可思議的清晰簡潔:

mapReducer data partitioner mapper reducer =
              let partitions = partitioner data
              in reduce reducer (map mapper partitions)

讓這樣的代碼支持并行計算或分布式并行計算是輕而易舉的(對于本地并行計算,很多的功能包都支持pmap和preduce只需要利用函數(shù)式語言的一些簡單特性)凰狞。像maps, partitions, generators, streams, reductions, folds, 已以及 function chaining等概念在各種的函數(shù)式編程語言中都大同小異篇裁,所以,任何對Lisp, Haskell, OCaml赡若,甚至帶點函數(shù)式語言特征的語言Python和Ruby熟悉的人达布,都會很容易的理解這里面的思想精華。
  讓我們花點時間考慮一下逾冬,如何用一種面向?qū)ο蟮恼Z言黍聂,以一種常見的面向?qū)ο蟮哪J絹砬宄拿枋鲞@種架構(gòu)。至少你需要做的事情是定義用來描述mapper和reducer的聲明粉渠。如果你有好奇心分冈,請試著用你喜歡的面向?qū)ο笳Z言描述一個最小化的面向?qū)ο蟮腗apReduce。我發(fā)現(xiàn)那是非常羅嗦的霸株。如果使用Java風(fēng)格的語言雕沉,它會像這樣:

interface Mapper {
   B map(A input);
 }

 interface Reducer {
   Y reduce(X a, X b);
 }

 abstract class MapReduce {
   private Mapper mapper;
   private Reducer reducer;

   public MapReduce(Mapper map, Reducer reduce) {
     // ...
   }

   public run(SeqenceType data) {
     // ...
   }
 }

即使是沒有加入循環(huán)邏輯,這種缺乏函數(shù)式模式中常見的名詞和動詞的使用去件,使得MapReduce這種技術(shù)很難被定義坡椒。這種定義方式幾乎是滑稽可笑的扰路,但它能讓你想到函數(shù)式概念。另外一個好例子是Scala語言如何利用完備的Java Fork/Join 類庫倔叼,把它輕松的集成的自己的自有語法中汗唱。
  各有所求
  所以,我鼓勵任何想進步的程序員:請考慮學(xué)習(xí)一種函數(shù)式語言丈攒。Haskell和OCaml都是極好的選擇哩罪,F(xiàn)#和Erlang也相當(dāng)?shù)牟诲e。它們都不好學(xué)巡验,但也許這是個好事际插。努力弄清楚你遇到的復(fù)雜的概念,看看是否有其他人正在利用這些概念显设;經(jīng)常的框弛,你會在尋找這些不熟悉的概念的真正用意的時候?qū)崿F(xiàn)思想上的突破。
  當(dāng)你開始學(xué)的時候捕捂,請注意瑟枫,不要過于在意。就像其他任何需要你花時間和精力的事情一樣指攒,過度的在函數(shù)式編程上進行精力上的投資是很危險的慷妙。掉進了認知能力的陷阱后,你的投資會血本無歸幽七。你很容易會忘掉世界上還有無數(shù)種計算模型景殷,你更容易忘掉有多少種優(yōu)秀的軟件根本沒有使用任何的函數(shù)式概念。
  學(xué)習(xí)的道路會越來越難走澡屡,但從另一方面說,在你日常的編程中驶鹉,你會發(fā)現(xiàn)有越來越多的可以使用的重要概念和模型。對于這樣緊湊的編程風(fēng)格你會越來越適應(yīng)办绝,必然孕蝉,你也會對如何成為一名更好的軟件工程師有了新的認識降淮。
  補充
  有不少校對這篇文章的人在看完文章后都問了我一個同樣的問題:聽起來不錯搏讶,大衛(wèi),可是我應(yīng)該學(xué)習(xí)那種語言呢系吩?當(dāng)然,這是他們給我出的難題月弛。
  我想尊搬,如果你是一個很有經(jīng)驗的程序員,這最能應(yīng)付這個問題的答案是:選一種符合你的需求的幌墓。如果你需要在JVM上工作常侣,選擇Scala或Clojure。如果你想能快速的開發(fā)大型分布式軟件系統(tǒng)溯祸,選擇Erlang焦辅。如果你想要一種具有超強編譯器的超能干活的語言椿胯,請選擇Haskell或RCaml。如果你想要一種比Ruby或Python更有能力的原型工具前方,選擇Scheme惠险。
  請記住班巩,我們在這里要做這些的目的是為了實際的技能和自我進步十兢。如果你能騰出時間學(xué)這些,就走出你的安逸環(huán)境遥缕,挑戰(zhàn)自己单匣。
  因為我已經(jīng)學(xué)習(xí)了Lisp和Erlang,而且使用OCaml做專業(yè)工作码秉,我決定研究一下Haskell转砖,這完全是另外一個世界府蔗。我發(fā)現(xiàn)唯一能幫助我參透這種語言的途徑是依賴 Learn You A Haskell Real World Haskell 這兩本有用的指導(dǎo)材料姓赤。這些書寫的非常好仲吏,很有價值裹唆,而且可以免費在網(wǎng)上找到。如果你想試一下Haskell岖食,這些書可以當(dāng)作你的尋寶圖泡垃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蔑穴,一起剝皮案震驚了整個濱河市惧浴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纵朋,老刑警劉巖茄袖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宪祥,死亡現(xiàn)場離奇詭異,居然都是意外死亡藏澳,警方通過查閱死者的電腦和手機翔悠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門凉驻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來复罐,“玉大人效诅,你說我怎么就攤上這事乱投∏瓯啵” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長钮惠。 經(jīng)常有香客問我素挽,道長,這世上最難降的妖魔是什么缩赛? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任辩昆,我火速辦了婚禮物喷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扇丛。我一直安慰自己帆精,他們只是感情好卓练,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布襟企。 她就那樣靜靜地躺著狮含,像睡著了一般几迄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上木羹,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天坑填,我揣著相機與錄音弛姜,去河邊找鬼。 笑死蚪黑,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的忌穿。 我是一名探鬼主播掠剑,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼井佑,長吁一口氣:“原來是場噩夢啊……” “哼眠寿!你這毒婦竟也來了盯拱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤宁舰,失蹤者是張志新(化名)和其女友劉穎蛮艰,沒想到半個月后壤蚜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡实柠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了钢拧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片源内。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖卿嘲,靈堂內(nèi)的尸體忽然破棺而出夫壁,到底是詐尸還是另有隱情盒让,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布邑茄,位于F島的核電站姨蝴,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏撩扒。R本人自食惡果不足惜似扔,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望搓谆。 院中可真熱鬧炒辉,春花似錦、人聲如沸泉手。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斩萌。三九已至缝裤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颊郎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工检眯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人避凝。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吊履。 傳聞我的和親對象是個殘疾皇子腾窝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容