奧推網

選單
科技

函數語言程式設計終於成為了主流!

摘要:面向物件程式設計和指令式程式設計仍然是現代軟體開發的主要正規化,而函數語言程式設計語言在生產程式碼庫中相對較少。隨著程式語言擴充套件對函數語言程式設計方法的支援,以及軟體開發新框架的迭代,函數語言程式設計正迅速透過各種不同的途徑進入越來越多的程式碼庫。

原文連結:https://github。com/readme/featured/functional-programming

宣告:本文為 CSDN 翻譯,轉載請註明來源。

作者 | KLINT FINLEY 譯者 | 彎月 責編 | 屠敏

出品 | CSDN(ID:CSDNnews)

Meddbase是一家於2005年創立的醫療保健軟體公司,Paul Louth在這家公司內建立了一支出色的開發團隊。但隨著公司的發展,他們的程式碼Bug數量也在增加。從某種程度上說,這是必然的結果。功能越多,程式碼越多;程式碼越多,Bug就越多。但缺陷率的增長速度超出了Louth的預期。

他表示:“我們看到越來越多相同型別的錯誤。很明顯某個地方出了問題,但我們不清楚究竟是什麼。我的直覺告訴我這個問題是由複雜性引起的。”

函數語言程式設計

他們使用的程式語言是C#,該語言剛剛添加了對語言整合查詢(LINQ)的支援。LINQ是一種查詢資料來源的語言,不僅可以查詢資料庫,而且還可以查詢程式碼庫中的物件。LINQ將函數語言程式設計正規化引入了C#,瞭解LINQ可以幫助你瞭解更多關於函數語言程式設計的知識。

函式是可在程式中重複完成特定任務的一段程式碼,可以避免重複編寫相同功能的程式碼,是一種程式設計標準。例如,你可以編寫一個根據圓的直徑計算周長的函式,或者編寫一個根據某人的出生日期計算星座的函式。

但是,正如Cassidy Williams(Netlify遠端開發者體驗與教育主管)在ReadME專案的函數語言程式設計指南中寫道,函數語言程式設計不僅僅是編寫函式,這是一種強調使用“純函式”編寫程式的範例,即無狀態的函式,在輸入相同的情況下總能返回相同的結果,而且在返回結果時不會產生“副作用”。換句話說,純函式不會更改任何現有資料或修改應用程式的其他邏輯。例如,如果計算圓周的函式修改了一個全域性變數,那麼它就不是純函數了。

在函數語言程式設計中,資料通常被視為是不可變的。例如,用函式式編寫的程式不會修改陣列的內容,而是會生成一個修改後的陣列副本。與資料結構和邏輯交織在一起的面向物件程式設計不同,函數語言程式設計強調資料和邏輯的分離。

Remote的開發者體驗負責人Williams寫道:“在考慮結構良好的軟體時,你可能會想到易於編寫、易於除錯並且包含很多可重複使用功能的軟體,而這說的就是函數語言程式設計!”

對於需要負責不斷增長的大型程式碼庫的團隊來說,函數語言程式設計是一個福音。由於編寫的程式碼具有很少副作用,且資料結構不會變化,因此負責程式碼庫某個部分的程式設計師不太可能破壞另一個程式設計師正在開發的功能。此外,追蹤錯誤也更加容易,因為程式碼中可以發生變化的地方很少。

隨著Louth對函數語言程式設計的深入研究,他意識到這種方法可以解決大型面向物件程式碼庫所面臨的一些問題,就好像他們團隊遇到的問題。然而,遇到此類問題的人不止他一個。在過去十年中,隨著越來越多的開發人員和組織尋找方法來控制軟體的複雜度,渴求構建更安全、更強大的軟體,人們對函數語言程式設計的興趣呈爆炸式增長。

Williams表示:“在真正瞭解函數語言程式設計後,我就不打算再使用其他正規化了。”實際上,他在大學期間使用LISP的衍生程式語言Scheme和Racket 時就愛上了函數語言程式設計。“面向物件程式設計很不錯,至今仍有很多人使用。但很多開發人員在接觸函數語言程式設計後,就會成為忠實的粉絲。”

當然,面向物件程式設計和指令式程式設計仍然是現代軟體開發的主要正規化,而Haskell和Elm之類的“純”函數語言程式設計語言在生產程式碼庫中相對較少。但隨著程式語言擴充套件對函數語言程式設計方法的支援,以及軟體開發新框架的迭代,函數語言程式設計正迅速透過各種不同的途徑進入越來越多的程式碼庫。

函數語言程式設計在主流語言中的興起

函數語言程式設計的起源可以追溯到20世紀50年代後期LISP程式語言的建立。儘管幾十年來LISP及其衍生語言(如Common LISP和Scheme)一直有一批忠實的追隨者,但到了70~80年代,隨著面向物件程式設計的興起,函數語言程式設計黯然失色。

到了2010年,隨著程式碼庫規模的日漸壯大,很多團隊都面臨著與Louth開發團隊相同的問題,於是人們對函數語言程式設計的興趣再次高漲。

Scala和Clojure將函數語言程式設計引入到了Java虛擬機器,而F# 將這種正規化引入到了。NET。推特將他們的大部分程式碼遷移到了Scala,而Facebook則選用了Haskell和Erlang等古老的函式式語言來解決特定問題。

與此同時,人們對在JavaScript、Ruby和Python等面嚮物件語言中應用函數語言程式設計技術的興趣也在增長。《Elm in Action》一書的作者Richard Feldman表示:“所有這些語言都開始支援方便實現函式式風格的功能,幾乎每一種語言支援的正規化都在增加。”

2014年,蘋果公司推出了Swift,這是一種新的多正規化語言,包括對函數語言程式設計的強大支援。該語言的釋出證明,函數語言程式設計支援已成為新程式語言的必備特性,就像對面向物件程式設計的支援一樣。Feldman在2019年的一次題為“為什麼函數語言程式設計不是主流?”的演講中說,函數語言程式設計馬上就要成為主流了。或者至少是主流的一部分。他說:“有些事情發生了變化,在90年代人們不認為這種風格是積極的,而如今它是積極的想法已經成為一種主流。”

對函數語言程式設計的支援級別和性質因語言而異,但有一項特定功能已成為標準。Remote後端工程師Tobias Pfeiffer表示:“可以說,有一項功能已經勝出,那就是高階函式,即接受或返回另一個函式的函式。你可以透過這種方式建立函式塊來優雅地解決問題。”

由於對高階函式的支援,如今開發人員可以將函數語言程式設計引入到自己的程式碼庫,而無需重新構建現有應用程式。當Louth團隊決定轉而使用函數語言程式設計模型時,他們決定使用F#編寫應用程式中的新程式碼,因為它提供了強大的函式式支援,而且還可以與。NET平臺保持相容。對於已有的C#程式碼,他們決定使用支援函數語言程式設計的語言,同時還會使用Language-ext(這是Louth自己編寫的函式式C#開源框架)。

Louth表示:“我們不想推倒一切重寫,因此在現有程式碼的基礎之上新增新功能時,我們會按照函數語言程式設計正規化來編寫。”

對於某些人來說,使用Java、JavaScript或C#等面向物件的語言進行函數語言程式設計感覺就像逆流而上。Arista Networks的工程經理Gabriella Gonzalez說:“語言可以引導你採用某些解決方案或風格。在Haskell中,阻力最小的方法是函數語言程式設計。你可以在Java中進行函數語言程式設計,但肯定不是最順利的方式。”

對於一些混合正規化來說,一個更大的問題是,如果程式碼中包含其他程式設計風格,那你就無法獲得純函式的保證。Williams表示:“如果你正在編寫的程式碼可能有副作用,那麼就不再是函式式了。你或許可以依賴部分程式碼庫。我編寫了各種非常模組化的函式,因此沒有任何程式碼會影響到它們。”

使用嚴格的函數語言程式設計語言可以降低在程式碼中意外引入副作用的可能性。Louth表示:“使用C#之類的語言編寫函式式程式碼的關鍵是你必須小心,因為你可以走捷徑,一旦你的程式碼不是純函式式編,那麼就會導致混亂。Haskell會強制你編寫函式式的程式碼,可以保證你的程式碼不出亂子。”這就是Louth團隊在一些新專案中使用Haskell的原因。

但純粹與否往往是主觀感受。Pfeiffer說:“LISP是最早的函數語言程式設計語言,但它具有可變的資料結構。”即使你的語言是純函式式,而且使用不可變的資料結構,但在接受使用者輸入的那一刻就有可能引入“雜質”。雖然使用者輸入可能包含“不純”的元素,但大多數程式都離不開使用者輸入,所以純粹是有限度的。Haskell管理使用者輸入和其他不可避免的“雜質”的方法是給程式碼貼上明確的標籤,並保證隔離,但不同的語言所劃定的界限有所不同。

拓展函式式思維

儘管現如今大多數主要程式語言都可以使用函數語言程式設計,但開發人員不一定會利用這些特性。函數語言程式設計的思維方式與命令式或面向物件程式設計截然不同。Williams表示:“讓我大吃一驚的是,你不能在函數語言程式設計中採用傳統的資料結構。我不必為一棵樹建立一個物件,直接使用樹就可以。感覺應該是不行,但確實可行。”

JavaScript庫React是如今開發人員接觸這種新思維方式的主要方式。由於React接受很多可變性,因此最好是把React視為“近似於函式式”,但生態系統確實支援這種方式,而且還鼓勵人們將函數語言程式設計作為常見問題的解決方案,但以前人們肯定會尋求其他方式。

ClojureScript的維護者David Nolen在他的ReadME專案故事中寫道:“儘管React表面看起來是面向物件,但它率先為UI程式設計提供了函式式方法。”

例如,最近推出的React Hooks 是一組幫助開發人員管理狀態和副作用的函式,而Redux則大量採用了函式式方法。

Williams表示:“雖然React不是純函式式,但它鼓勵人們以函數語言程式設計的方式思考。例如,它為前端開發人員引入了map和reduce迴圈。自此,前端開發人員無需再編寫任何for迴圈。”

另一方面,Gonzalez則認為函數語言程式設計透過另一種途徑躋身主流之列:特定領域的語言。真正擅長解決某個問題的語言會更加容易被採納。例如,Nix包管理系統的表示式語言。“它是甚至比Haskell更純粹的函式式語言,因為使用這種語言編寫的程式碼更加難以附帶有副作用或可變性。”Nix的用途很單一,至少不適合構建Web伺服器。它的目的只有一個:構建包。但由於它是為這種特定任務而構建的,所以需要構建工具的開發人員都會使用它,即使他們不會嘗試使用函數語言程式設計語言。“我認為,隨著時間的推移,通用語言會越來越少,而專用語言越來越多,其中許多都是函式式語言。”

函數語言程式設計的未來

與軟體開發領域的許多其他方面一樣,函數語言程式設計的未來在很大程度上取決於圍繞函式式語言和概念構建的開源社群。例如,採用純函數語言程式設計的一個障礙是,面向物件程式設計或指令式程式設計的庫在數量上擁有絕對優勢。從Python的數學與科學計算包到Node。js的Web框架,很多解決常見問題的程式碼庫都不是以函式式風格編寫的,但我們無法因此而棄用它們。Louth團隊中使用Haskell時就遇到了這樣的問題:“Haskell有一個非常成熟的生態系統,但我們的困擾在於無法使用一些非專業的庫。”

為了克服這個障礙,函數語言程式設計社群必須團結起來,建立新的庫,幫助開發人員選擇函數語言程式設計。

從language-ext庫到Redux,再到Nix,許多人已經在努力中了。