【轉】爲何說面向對象編程和函數式編程都有問題

我不理解爲何人們會對面向對象編程和函數式編程作無休無止的爭論。就好象這類問題已經超越了人類智力極限,因此你能夠幾個世紀的這樣討論下去。通過這些年對編程語言的研究,我已經清楚的看到了問題的答案,因此,我常常的發現,人們對這些問題作的都是一些抓不住要領、無心義的爭論。程序員

簡言之,不管是面向對象編程仍是函數式編程,若是你走了極端,那都是錯誤的。面向對象編程的極端是一切都是對象(純面向對象)。函數式編程的極端是純函數式編程語言編程

面向對象編程的問題

面向對象的問題在於它對「對象」的定義,它試圖將全部事情就歸入到這個概念裏。這種作法極端化後,你就得出來一個一切皆爲對象思想。但這種思想是錯誤的,由於設計模式

有些東西不是對象。函數就不是對象。安全

也許你會反駁,在Python和Scala語言裏,函數也是對象。在Python中,全部的含有一個叫作__call__的方法的對象其實都是函數。相似的,在Scala語言裏,函數是擁有一個叫作apply方法的對象。可是,通過認真的思考後,你會發現,它混淆了源祖和衍生物的概念。函數是源祖,包含函數的對象實際是衍生物。__call__apply它們自身首先就是要定義的所謂「函數對象」。Python和Scala其實是綁架了函數,把它們監禁在「對象」裏,而後打上「__call__」 和 「apply」 標籤,把它們稱做「方法」。固然,若是你把一個函數封裝到對象裏,你能夠像使用一個函數那樣使用對象,但這並不意味着你能夠說」函數也是對象「數據結構

大多數的面嚮對象語言裏都缺少正確的實現一等(first-class)函數的機制。Java語言是一個極致,它徹底不容許將函數看成數據來傳遞。你能夠將所有的函數都封裝進對象,而後稱它們爲「方法」,但就像我說的,這是綁架。缺少一等函數是爲何Java裏須要這麼多「設計模式」的主要緣由。一旦有了一等函數,你將再也不須要大部分的這些設計模式。app

函數式編程的問題

類似的,函數式編程走向極端、成爲一種純函數式編程語言後,也是有問題的。爲了討論這個問題,咱們最好先理解一下什麼是純函數式編程語言。出於這個目的,你可能須要閱讀一下Amr Sabry先生(他是個人博士導師)的What is a Purely Functional Language。概述一下就是,純函數式編程語言是錯誤的,由於編程語言

有些東西不是純的。反作用是真實存在的。wordpress

所謂純函數,基本上就是忽略了物質基礎(硅片、晶體等)表現的特性。純函數式的編程語言試圖經過函數——在函數中傳入傳出整個宇宙——來從新實現整個宇宙。但物理的模擬的是有區別的。「反作用」是物理的。它們真實的存在於天然界中,對計算機的效用的實現起着不可或缺的做用。利用純函數來模擬它們是註定低效的、複雜的、甚至是醜陋的。你是否發現,在C語言裏實現一個環形數據結構或隨機數發生器是多麼的簡單?但使用Haskell語言就不是這樣了。函數式編程

還有,純函數編程語言會帶來巨大的認知成本。若是你深刻觀察它們,你會看到monads使程序變得複雜,難於編寫,並且monad的變體都是拙劣的修改。monads跟Java的「設計模式」具備相同的精神本質。使用monad來表現反作用就像是visitor模式來寫解釋器。你是否發現,在不少其它語言裏很簡單的事情,放到Haskell語言就變成了一個課題來研究如何實現?你是否常常會看到一些有着諸如「用Monadic的方式解決一個已經解決的問題」這樣標題的論文?有趣的是,Amr Sabry先生一塊兒合著了這樣一篇論文。他試圖用Haskell語言從新實現Dan Friedman的miniKanren,但他不知道如何構造這些monads。他向Oleg Kiselyov——公認的世界上對Haskell類型系統知識最淵博的人——求教。並且你可能不知道,Amr Sabry先生應該是世界上對純函數編程語言知識最淵博的人了。他們在 Oleg 的幫助下解決了疑難後一塊兒合著了這篇論文。諷刺的是,Dan Friedman——這個程序的原做者——在使用Scheme語言開發時卻沒有遇到任何問題。我在Dan的代碼基礎上從新實現了miniKanren,增長了一個複雜的負操做。爲了實現這個,我須要使用約束式邏輯編程和其它一些高級的技巧。鑑於用Haskell語言重寫基本的miniKanren將兩位世界級程序員都難倒了的事實,我不敢想象若是用Haskell的monads如何能實現這些。函數

有些人認爲monads的價值在於,它們「圈定」了反作用的範圍。但若是monads不能真正的使程序變得易於分析或更安全,這種「圈定」有什麼用呢?事實上就是沒用處。自己就跟反作用同樣難於分析理解。沒有一種東西能夠說monads能使其簡單而靜態分析辦不到的。全部的靜態分析研究者都知道這點。靜態分析利用了monads的本質,但卻去除了程序員編寫monads代碼的負擔——而不是增長負擔。固然,過分的反作用會使程序很難分析,但你也可使用C語言寫出純函數,例如:

int f(int x) {
    int y = 0;
    int z = 0;
    y = 2 * x;
    z = y + 1;
    return z / 3;
}

你用匯編語言也能作到這些。純函數並不專屬於純函數式編程語言。你能夠用任何語言寫出純函數,但重要的是,你必須也應該容許反作用的存在。

回首歷史,你會發現,數學上的理想主義是純函數編程語言的背後推進力。數學函數簡單漂亮,但不幸的是,它們只是在你構建原始純粹的模型時纔好用。否者它們會變得很醜陋。不要被「範疇論」等標語嚇倒。我對範疇論瞭解不少。即便是範疇理論學家本身也稱其爲「抽象無心義」,由於它們基本上就是用一種怪誕的方式告訴你一些你已經知道的事情!若是你讀過Gottlob Frege的文章Function and concept,你會吃驚的發現,在他的這篇論文前的大多數數學家都錯誤的理解了函數,而這僅僅是剛剛100多年前的事。事實上,數學語言上的不少事情都是有問題的。特別是微積分方面。編程語言的設計者們沒有理由要盲目的學習數學界。

不要盲目的愛上你的模型

不管任何事情,當走向極端時都是有害的。極端化時,面向對象編程和函數式編程都試圖把整個世界裝入它們的特有模型中,但這個世界是在徹底不依賴咱們的大腦思考的狀況下運轉的。若是覺得你有一個錘子,就把全部東西都當成釘子,這明顯是不對的。只有經過認清咱們的真實世界,才能擺脫信仰對咱們的束縛。

不要讓世界適應你的模型。讓你的模型適應世界。

相關文章
相關標籤/搜索