函數式編程很難,這正是你要學的緣由

很奇怪不是,不多有人天天都使用函數式編程語言。 若是你用Scala,Haskell,Erlang,F#或某個Lisp方言來編程,極可能沒有公司會花錢聘你。這個行業裏的絕大部分人都是使用像 Python,Ruby,Java或C#等面向對象的編程語言——它們用起來很順手。不錯,你也許會偶然用到一兩個「函數式語言特徵」,例如 「block」,但人們不會去作函數式編程。 html

然而,不少年來,咱們一直被教導說函數式編程語言很好很棒。我仍然記得當我第一次閱讀ESR的著名的關於學習Lisp語言的論文時的困惑。也許大多數的人對Paul Graham 的《Beating The Averages》這篇文章更加熟悉: 程序員

使用Lisp開發使咱們的開發週期迭代的如此之快,以致於有時當競爭對手在新聞發佈會上推出他們的新功能一兩天後,咱們就能複製出一樣的功能。當報道產品發佈的新聞記者打電話給咱們時,咱們的產品已經擁有了一樣的功能特徵。 算法

那些皈依函數式編程的人中,一直常見的考慮是:學習這種新的、函數式的語言「對你有好處」;就像是某些人建議說天天30分鐘的健身房活動會「讓你的 身體健康」同樣。但這也同時暗示了這樣作的難度和須要的付出。Lisp語言跟Haskell、Ocaml和Scala語言不一樣,被認爲是出了名的難學,可 以說是臭名昭著。文雅的人說這是Lisp語言的「深度&廣度」的體現。不文雅的人說這是「意淫」或「玩弄學術」或簡單的「不必」。我認爲,它的 難度跟你對它熟不熟悉有關,並且,這種難度是一種重要指標顯示:學習這樣的一種語言會讓你編程更有效率、能力更強。 編程

它給你的初次印象不友善 數據結構

我7歲時就開始編程,在漫長無聊的郊區夏季裏,在我祖父的計算機上瞎搞一氣。我學了BASIC,用它在屏幕上畫一個蹦跳的球。我學了Pascal, 用它寫了一個能經過PC喇叭放音樂的程序。大概10歲時我學了C語言,但遇到了一堵越不過去的牆,直到我上了高中。那就是:指針。即便不算這些該死的指 針,我寫、讀、學習、練習中,一樣遭遇無數的失敗。我把祖父的硬盤給毀掉了兩次(一次屬意外),最後弄得很多次要本身重裝操做系統。我失敗,一遍遍的失 敗。 架構

也許你也有跟我類似的故事,也許是徹底不一樣的一個。但我想,差很少全部學過編程的人都有過遇到困難的經歷。咱們在學了一些基本知識後,必然會遇到一些公認的概念上的關口,好比「指針」。不少計算機科學教授會把指針描述爲他們課程上的過濾網。若是你想成爲一名優秀的程序員,你必需要能理解指針。不多人能輕鬆的掌握它們。大多數人,包括我,則須要不斷的練習和參考例子來理解什麼是指針、爲何它們很重要。 app

這種艱難的努力過程不是偶然的,是一種幾乎廣泛的現象。指針是一種很是強大和基礎功能的概念。學會它能讓你成爲一名更好的程序員,能讓你的思考更加形象化。即便你使用的語言並不提供指針這樣的特徵,但跟指針相似的數據結構和概念卻隨處可見。 編程語言

新奇事物 分佈式

一旦你學會了幾種語言後,全部的語言都開始看起來都很類似。知道Python的人學習Ruby可能不會遇到太多的問題,知道Java的人學習C#會 感到很熟悉。不錯,也有意外的地方。Ruby愛好者在學習Python時會對它的comprehension感到吃驚,Java用戶會對C#裏的委派摸不着頭腦。仍是那句話,若是你只瞟一眼,它們都很類似。我能夠打保票的說,若是你還未曾有過這樣的認識,一旦你學了一種Lisp語言,你會發現全部的Lisp變種都很類似。 函數式編程

有人說,大部分人第一次使用Haskell或Ocaml時都徹底的不知所措。見鬼了,在Haskell裏,連分號都跟別人不同。這並非語法的問題;Haskell和ML語言徹底基於一種不一樣的概念、一種新的語言範式。你須要用不一樣的方式開發應用,不一樣的方式組織應用,不一樣的方式擴展應用。

不少這樣的新概念都具備難以想象的強大力量。Haskell裏的Monads 是跟指針同樣基礎且強大的概念(你極可能在不知道它叫什麼的狀況下就已經使用過它們了)。因此,跟學了Java後再學C#不同,有志向學習函數式語言的 人須要往回走的更遠,去學習更加基礎的概念後才能接下去學習。就像是徹底再學習一次指針。而且,就像是當年咱們剛開始學習編程同樣,一些很大的概念看起來 會讓人迷惑茫然,讓人沮喪,直到你去攻克(以及失敗)它們。

吃下你的藥丸,找到你的藥劑師

儘管很差學,但我堅信,學習這些函數式編程語言會在職業上對你有好處。我相信有些人讀到這點時會眼睛翻起來向天看,很難想象出這些monoids 或 monad 會對他們在使用Java或C#時有用處。對我而言,我已經不驚奇於因爲這樣的思惟而阻止他們學習函數式語言的現象;他們須要學習一種跟指針和遞歸同樣基礎 的新概念。他們須要有一種只有專業人員在完成清晰的商業目標時才具備的耐心和鬥志。不多人能在過了可塑的年齡後還受得了挫折——一次又一次的挫折——不然 咱們如今都早成專家了,不是嗎?

還有更復雜的東西,有大量的語言和算法研究都是用函數式語言實施的(尤爲是Haskell)。你很容易會被這些不熟悉的概念——例如分類學理論half-finished abstractions,一些失敗的研究——弄的迷失方向。沒有一個清晰的指導(好比由一個實用主義的做者寫的一本好書),原本已經很困難的學習任務變的更加可怕。
這些疊加起來的複雜因素致使了不出意外的結果:不少人不情願在函數式編程學習中投入時間。很容易理解這種不情願,「我幹嗎不把花在學習這些東西的時間用在 實現什麼東西上呢?」但這種思路也代表了你永遠不肯意在任何新技術上浪費時間(只用本身熟悉的)。在一個像軟件技術這樣突飛猛進的產業裏,我不認爲這是正 確的判斷。

眼見爲實

學習一種函數式編程語言最顯而易見的好處是,你能學會這種類型語言中的函數式概念。它能幫助你的大腦,讓它具備能很是清晰的思考和處理一些驚人的重 大概念的能力。這並非函數式編程具備魔法;各類語言和範式的出現都是爲了應對某一特定類別的問題。函數式編程的殺手鐗正是應對了當今世界上日益增加的並 行性編程和元數據編程趨勢。

例如,咱們研究一個簡化的、本地版本化的Google著名的MapReduce範例。用函數式方式描述這種範例是難以想象的清晰簡潔:

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

讓這樣的代碼支持並行計算或分佈式並行計算是垂手可得的(對於本地並行計算,不少的功能包都支持「pmap」和「preduce「——只須要利用函 數式語言的一些簡單特性)。像maps, partitions, generators, streams, reductions, folds, 已以及 function chaining等概念在各類的函數式編程語言中都大同小異,因此,任何對Lisp,Haskell,OCaml,甚至帶點函數式語言特徵的語言—— Python和Ruby熟悉的人,都會很容易的理解這裏面的思想精華。

讓咱們花點時間考慮一下,如何用一種面向對象的語言,以一種常見的面向對象的模式來清楚的描述這種架構。至少你須要作的事情是定義用來描述 mapper和reducer的聲明。若是你有好奇心,請試着用你喜歡的面嚮對象語言描述一個最小化的「面向對象」的MapReduce。我發現那是很是 羅嗦的。若是使用Java風格的語言,它會像這樣:

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) {     // ...   } }

即便是沒有加入循環邏輯,這種缺少函數式模式中常見的名詞和動詞的使用,使得MapReduce這種技術很難被定義。這種定義方式幾乎是滑稽好笑的,但它能讓你想到函數式概念。另一個好例子是Scala語言如何利用完備的Java Fork/Join 類庫,把它輕鬆的集成的本身的自有語法中

各有所求

因此,我鼓勵任何想進步的程序員:請考慮學習一種函數式語言。Haskell和OCaml都是極好的選擇,F#和Erlang也至關的不錯。它們都 很差學,但也許這是個好事。努力弄清楚你遇到的複雜的概念,看看是否有其餘人正在利用這些概念;常常的,你會在尋找這些不熟悉的概念的真正用意的時候實現 思想上的突破。

當你開始學的時候,請注意,不要過於在乎。就像其餘任何須要你花時間和精力的事情同樣,過分的在函數式編程上進行精力上的投資是很危險的。掉進了認知能力的陷阱後你的投資會血本無歸。你很容易會忘掉世界上還有無數種計算模型,你更容易忘掉有多少種優秀的軟件根本沒有使用任何的函數式概念。
學習的道路會愈來愈難走,但從另外一方面說,在你平常的編程中,你會發現有愈來愈多的可使用的重要概念和模型。對於這樣緊湊的編程風格你會愈來愈適應,必然,你也會對如何成爲一名更好的軟件工程師有了新的認識。

補充

有很多校對這篇文章的人在看完文章後都問了我一個一樣的問題:「聽起來不錯,大衛,但是我應該學習那種語言呢?」固然,這是他們給我出的難題。

我想,若是你是一個頗有經驗的程序員,這最能「應付」這個問題的答案是:「選一種符合你的需求的」。若是你須要在JVM上工做,選擇Scala或 Clojure。若是你想能快速的開發大型分佈式軟件系統,選擇Erlang。若是你想要一種具備超強編譯器的超能幹活的語言,請選擇Haskell或 RCaml。若是你想要一種比Ruby或Python更有能力的原型工具,選擇Scheme。

請記住,咱們在這裏要作的這些目的是爲了實際的技能和自我進步。若是你能騰出時間學這些,就走出你的安逸環境,挑戰本身。

由於我已經學習了Lisp和Erlang,並且使用OCaml作專業工做,我決定研究一下Haskell,這徹底是另一個世界。我發現惟一能幫助我參透這種語言的途徑是依賴Learn You A HaskellReal World Haskell 這兩本有用的指導材料。這些書寫的很是好,頗有價值,並且能夠免費在網上找到。若是你想試一下Haskell,這些書能夠看成你的尋寶圖。

相關文章
相關標籤/搜索