函數式編程很難,這正是你要學習它的原因

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

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

使用Lisp開發使我們的開發周期迭代的如此之快,以至于有時當競爭對手在新聞發布會上推出他們的新功能一兩天后,我們就能復制出同樣的功能。當報道產品發布的新聞記者打電話給我們時,我們的產品已經擁有了同樣的功能特征。

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

它給你的初次印象不友善

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

也許你也有跟我相似的故事,也許是完全不同的一個。但我想,差不多所有學過編程的人都有過遇到困難的經歷。我們在學了一些基本知識后,必然會遇到一些公認的概念上的關口,比如“指針”。很多計算機科學教授會把指針描述為他們課程上的過濾網。如果你想成為一名優秀的程序員,你必須要能理解指針。很少人能輕松的掌握它們。大多數人,包括我,則需要不斷的練習和參考例子來理解什么是指針、為什么它們很重要。

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

新奇事物

一旦你學會了幾種語言后,所有的語言都開始看起來都很相似。知道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 datain 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 Haskell 和 Real World Haskell 這兩本有用的指導材料。這些書寫的非常好,很有價值,而且可以免費在網上找到。如果你想試一下Haskell,這些書可以當作你的尋寶圖。


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/452186.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/452186.shtml
英文地址,請注明出處:http://en.pswp.cn/news/452186.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

函數依賴

設R(U)是一個屬性集U上的關系模式,X和Y是U的子集。若對于R(U)的任意一個可能的關系r,r 中不可能存在兩個元組在X上的屬性值相等, 而在Y上的屬性值不等, 則稱“X函數確定Y”或“Y函數依賴于X”,記作X→Y。 X→Y&#x…

Java面試——線程池

1、類比介紹 假如有一個工廠,工廠里面有10個工人,每個工人同時只能做一件任務。 因此只要當10個工人中有工人是空閑的,來了任務就分配給空閑的工人做; 當10個工人都有任務在做時,如果還來了任務,就把任務進…

C#關鍵字的使用

params object[] 用于函數多參數的定義public static void Write(string format, params object[] arg);explicit 關鍵字用于聲明必須使用強制轉換來調用的用戶定義的類型轉換運算符。 例如,在下面的示例中,此運算符將名為 Fahrenheit 的類轉換為名為 Ce…

maven 中 pom.xml 配置文件標簽說明,dependencyManagement和dependencies區別

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 參考:http://zhaoshijie.iteye.com/blog/2094478http://blog.csdn.net/cpf2016/article/details/45674377 還有一篇轉載文章…

學成在線--17.我的課程

文章目錄一.需求分析二.API接口三.PageHelper1.PageHelper介紹2.添加依賴3.配置pageHelper四.Dao1.mapper 接口2.mapper.xml映射文件3.測試Dao五.Service六.Controller七.前端1.創建course_list.vue2.路由3.定義API方法4.前端視圖course_list.vue詳解1)API調用--在視…

碼是數據系統中的基本概念。所謂碼就是能唯一標識實體的屬性或屬性集合,他是整個實體集的性質,而不是單個實體的性質。 主屬性與非主屬性 包含在任何一個候選碼中的屬性 ,稱為主屬性(Prime attribute)。 不包含在任何…

關于C編程的一點感受

剛畢業的時候用了兩個多月的C語言編程,總的來說對它還是很有感受的,C是一個過程式語言,沒有像C,Java等OOP語言這樣那樣的一系列的規則和限制;它比較靈活,簡潔,高效;這些是給我的印象最深的。這是…

如何打造高效的多任務、高并發的網絡服務器系統?

同一個功能的軟件,不同的團隊,不同工程師去實現,肯定是千差萬別,甚至從根本上完全不同。所以軟件開發在未來很長時間內仍然是一項工匠的手工勞動,尤其像多任務,高并發,偏底層這種對實現技巧比較…

BZOJ.2780.[SPOJ8093]Sevenk Love Oimaster(廣義后綴自動機)

題目鏈接 \(Description\) 給定n個模式串,多次詢問一個串在多少個模式串中出現過。(字符集為26個小寫字母) \(Solution\) 對每個詢問串進行匹配最終會達到一個節點,我們需要得到這個節點所代表的子串出現在多少個模式串中。 建立廣義后綴自動機。每次插入…

BigDecimal 加減乘除運算

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 java.math.BigDecimal。BigDecimal一共有4個夠造方法,讓我先來看看其中的兩種用法: 第一種:BigDeci…

主碼 超碼 候選碼

碼是數據系統中的基本概念。所謂碼就是能唯一標識實體的屬性,他是整個實體集的性質,而不是單個實體的性質。它包括超碼,候選碼,主碼。   超碼是一個或多個屬性的集合,這些屬性可以讓我們在一個實體集中唯一地標識一…

學成在線--18.新增課程(課程分類查詢)

文章目錄一.需求分析二.課程分類查詢介紹三.數據結構四.數據格式五.數據模型六.Api接口七.服務器端1.Dao1)定義mapper2)定義mapper映射文件2.Service3.Controller八.接口測試一.需求分析 用戶操作流程如下: 1、用戶進入“我的課程”頁面&…

給程序員們的工資報價提醒

在薪水上討價還價的方式有很多種,我要說的這一點也許并不是最好的。然而,如果使用的得當,會收到很好的效果。如果你正在跟一家公司接觸(沒有經過職業中介),而且事情看來很順利,進度很快,你要保持這種面試的…

POI 方式-excle 表格導出實現-java-poi

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 效果&#xff1a; jsp 頁面 用的Bootstrap &#xff1a; <li class"dropdown"> <a href"javascript:void(0)…

02-css的選擇器

css的選擇器&#xff1a;1.基本選擇器 2.高級選擇器 基本選擇器包含&#xff1a; 1.標簽選擇器標簽選擇器可以選中所有的標簽元素&#xff0c;比如div&#xff0c;ul&#xff0c;li &#xff0c;p等等&#xff0c;不管標簽藏的多深&#xff0c;都能選中&#xff0c;選中的是所有…

iphoneX樣式兼容

// 1.viewport meta 標簽增加屬性viewport-fitcover // 2.body元素增加樣式 body { padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); } // 3.如有fixed底部的元素&#xff0c;也增加上面樣式 xxx { padding-bottom: constant…

學成在線--19.新增課程(數據字典)

文章目錄一.介紹二.數據模型三.數據模型類四.字典查詢API接口五.服務器端1.Dao2.Service3.Controller一.介紹 在新增課程界面需要選擇課程等級、課程狀態等&#xff0c;這些信息統一采用數據字典管理的方式。 本項目對一些業務的分類配置信息&#xff0c;比如&#xff1a;課程…

范式簡介

范式是符合某一種級別的關系模式的集合。關系數據庫中的關系必須滿足一定的要求。滿足不同程度要求的為不同范式。范式的種類&#xff1a; 第一范式(1NF) 第二范式(2NF) 第三范式(3NF) BC范式(BCNF) 第四范式(4NF) 第五范式(5NF) 一個低一級范式的關系模式&#xff0c;通過模…

程序員的進化

對于很多同學來說&#xff0c;他們對程序員的職業生涯非常關注。而這本質上是一個進化的過程。我們將如何進化&#xff1f;在每個進化階段我們應該如何提高自己&#xff1f;下面的文章根據我自己的切身經歷和閱讀過的書&#xff0c;為程序員每個階段的進化提供了不同的學習思路…

【樹形dp】vijos1144小胖守皇宮

細節很精妙 描述 huyichen世子事件后&#xff0c;xuzhenyi成了皇上特聘的御前一品侍衛。 皇宮以午門為起點&#xff0c;直到后宮嬪妃們的寢宮&#xff0c;呈一棵樹的形狀&#xff1b;某些宮殿間可以互相望見。大內保衛森嚴&#xff0c;三步一崗&#xff0c;五步一哨&#xff0c…